<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="pragma" content="no-cache" />
    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate" />
    <meta http-equiv="expires" content="0" />
    <title>花卷猫</title>
</head>
<body>
    <video id="myvideo" src="" controls="controls" width="500" height="300" style="position:fixed;left:0px;top:0px;z-index:999;display:none;" onmousedown="javascript:this.style.display='none';" ontouchstart="javascript:this.style.display='none';" loop="loop" muted></video>
    <canvas id="exampleCanvas" width="400" height="700" style="position: fixed; left: 0px; top: 0px;" />
    <script type="text/javascript">
    /*
    * 坐标结构
    */
    class FP {
        // 构造函数
        constructor(ix, iy) {
            this.x = ix;
            this.y = iy;
        }
    };
    /*
    * 大小结构
    */
    class FS {
        // 构造函数
        constructor(icx, icy) {
            this.cx = icx;
            this.cy = icy;
        }
    };
    /*
    * 矩形结构
    */
    class FR {
        // 构造函数
        constructor(ileft, itop, iright, ibottom) {
            this.l = ileft;
            this.t = itop;
            this.r = iright;
            this.b = ibottom;
        }
    };
    /*
    * 转换颜色
    */
    function ccr(inColor) {
        if (inColor.indexOf("rgba(") != -1) {
            let inStrs = inColor.replace("rgba(", "").replace(")", "");
            let strs = inStrs.split(',');
            if (strs.length >= 4) {
                let a = parseFloat(strs[3]);
                a /= 255;
                return "rgba(" + strs[0] + "," + strs[1] + "," + strs[2] + "," + a + ")";
            }
        }
        return inColor;
    }

    /*
    * 绘图结构
    */
    class FCPaint {
        constructor() {
            this.cancelClick = false; //是否退出点击
            this.canvas = null; //视图
            this.context = null; //绘图上下文
            this.ds = "light"; //默认样式 light:白色 dark:黑色
            this.firstTouch = false; //是否第一次触摸
            this.focusedView = null; //焦点视图
            this.isPath = false; //是否路径
            this.isMobile = false; //是否移动端
            this.moveTo = false;
            this.ratio = 1; //缩放比例
            this.sfX = 1; //横向缩放比例
            this.sfY = 1; //纵向缩放比例
            this.secondTouch = false; //是否第二次触摸
            this.systemFont = "Arial"; //系统字体
            this.touchDownView = null; //触摸的视图
            this.touchMoveView = null; //触摸移动的视图
            this.touchDownPoint = null; //触摸的坐标
            this.tpf = new FP(0, 0); //第一次触摸的点
            this.tsp = new FP(0, 0); //第二次触摸的点
            this.views = new Array(); //视图集合
            this.onClickGridCell = null; //点击单元格的回调
            this.onClickGridColumn = null; //点击列的回调
            this.onPaint = null; //重绘回调
            this.onPaintBorder = null; //重绘边线回调
            this.onPaintGridCell = null; //绘制单元格的回调
            this.onPaintGridColumn = null; //绘制表格列的回调
        }
        /*
        * 添加线
        * x1:横坐标1
        * y1:纵坐标1
        * x2:横坐标2
        * y2:纵坐标2
        */
        al(x1, y1, x2, y2) {
            if (!this.moveTo) {
                this.moveTo = true;
                this.context.moveTo(Math.round(x1 * this.sfX), Math.round(y1 * this.sfY));
            }
            this.context.lineTo(Math.round(x2 * this.sfX), Math.round(y2 * this.sfY));
        };
        /*
        * 开始路径
        */
        beginPath() {
            this.context.beginPath();
            this.isPath = true;
        };
        /*
        * 开始绘图
        * rect:区域
        */
        beginPaint(rect) {
            if (!this.context) {
                this.context = this.canvas.getContext("2d");
            }
            this.moveTo = false;
        };
        /*
        * 闭合路径
        */
        closeFigure() {
            this.context.closePath();
        };
        /*
        * 关闭路径
        */
        closePath() {
            this.moveTo = false;
        };
        /*
        * 绘制线
        * color:颜色
        * width:宽度
        * style:样式
        * x1:横坐标1
        * y1:纵坐标1
        * x2:横坐标2
        * y2:纵坐标2
        */
        dl(color, width, style, x1, y1, x2, y2) {
            width = Math.min(this.sfX, this.sfY) * width;
            this.context.beginPath();
            this.context.strokeStyle = ccr(color);
            this.context.lineWidth = width;
            if (this.context.lineWidth < 1) {
                this.context.lineWidth = 1;
            }
            if (style != 0) {
                this.context.setLineDash(style);
            }
            this.context.moveTo(Math.round(x1 * this.sfX), Math.round(y1 * this.sfY));
            this.context.lineTo(Math.round(x2 * this.sfX), Math.round(y2 * this.sfY));
            this.context.stroke();
            if (style != 0) {
                this.context.setLineDash([]);
            }
        };
        /*
        * 绘制路径
        * color:颜色
        * width:宽度
        * style:样式
        */
        dp(color, width, style) {
            width = Math.min(this.sfX, this.sfY) * width;
            if (style != 0) {
                this.context.setLineDash(style);
            }
            this.context.strokeStyle = ccr(color);
            this.context.lineWidth = width;
            if (this.context.lineWidth < 1) {
                this.context.lineWidth = 1;
            }
            this.context.stroke();
            if (style != 0) {
                this.context.setLineDash([]);
            }
        };
        /*
        * 绘制图片
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        */
        drawImage(i, left, top, right, bottom) {
            let w = right - left;
            let h = bottom - top;
            try{
                this.context.drawImage(i, Math.round(left * this.sfX), Math.round(top * this.sfY), Math.round(w * this.sfX), Math.round(h * this.sfY));
            }catch(err){

            }
        };
        /*
        * 绘制连续线条
        * color:颜色
        * width:宽度
        * style:样式
        */
        dpl(color, width, style, apt) {
            if(apt.length > 1){
                width = Math.min(this.sfX, this.sfY) * width;
                if (style) {
                    this.context.setLineDash(style);
                }
                this.context.strokeStyle = ccr(color);
                this.context.lineWidth = width;
                if (this.context.lineWidth < 1) {
                    this.context.lineWidth = 1;
                }
                this.context.beginPath();
                for(let i = 0; i < apt.length; i++){
                    let x = apt[i].x;
                    let y = apt[i].y;
                    if (this.sfX != 1 || this.sfY != 1){
                        x = this.sfX * x;
                        y = this.sfY * y;
                    }
                    if (i == 0){
                        this.context.moveTo(Math.round(x), Math.round(y));
                    }else{
                        this.context.lineTo(Math.round(x), Math.round(y));
                    }
                }
                this.context.stroke();
                if (style) {
                    this.context.setLineDash([]);
                }
            }
        };
       /*
        * 绘制多边形
        * color:颜色
        * width:宽度
        * style:样式
        */
        dpg(color, width, style, apt) {
            if(apt.length > 1){
                width = Math.min(this.sfX, this.sfY) * width;
                if (style) {
                    this.context.setLineDash(style);
                }
                this.context.strokeStyle = ccr(color);
                this.context.lineWidth = width;
                if (this.context.lineWidth < 1) {
                    this.context.lineWidth = 1;
                }
                this.context.beginPath();
                for(let i = 0; i < apt.length; i++){
                    let x = apt[i].x;
                    let y = apt[i].y;
                    if (this.sfX != 1 || this.sfY != 1){
                        x = this.sfX * x;
                        y = this.sfY * y;
                    }
                    if (i == 0){
                        this.context.moveTo(Math.round(x), Math.round(y));
                    }else{
                        this.context.lineTo(Math.round(x), Math.round(y));
                    }
                }
                this.context.closePath();
                this.context.stroke();
                if (style) {
                    this.context.setLineDash([]);
                }
            }
        };
        /*
        * 绘制椭圆
        * color:颜色
        * width:宽度
        * style:样式
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        */
        de(color, width, style, left, top, right, bottom) {
            width = Math.min(this.sfX, this.sfY) * width;
            let w = right - left;
            let h = bottom - top;

            if (style != 0) {
                this.context.setLineDash(style);
            }
            this.context.strokeStyle = ccr(color);
            this.context.lineWidth = width;
            if (this.context.lineWidth < 1) {
                this.context.lineWidth = 1;
            }
            let centerX = (left + (right - left) / 2) * this.sfX;
            let centerY = (top + (bottom - top) / 2) * this.sfY;
            if (this.context.ellipse) {
                this.context.beginPath();
                this.context.ellipse(centerX, centerY, (w / 2) * this.sfX, (h / 2) * this.sfY, 0, 0, Math.PI * 2);
                this.context.stroke();
            } else {
                let radius = Math.max(w, h) / 2;
                if(radius < 1){
                    radius = 1;
                }
                this.context.save();
                this.context.translate(centerX, centerY);
                if(radius > 1){
                    if (w > h) {
                        this.context.scale(1, h / w);
                    } else if (w < h) {
                        this.context.scale(w / h, 1);
                    }
                }
                this.context.beginPath();
                this.context.arc(0, 0, radius, 0, 2 * Math.PI, false);
                this.context.stroke();
                this.context.restore();
            }
            
            if (style != 0) {
                this.context.setLineDash([]);
            }
        };
        /*
        * 绘制矩形
        * color:颜色
        * width:宽度
        * style:样式
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        */
        dr(color, width, style, left, top, right, bottom) {
            width = Math.min(this.sfX, this.sfY) * width;
            let w = right - left;
            let h = bottom - top;
            if (style != 0) {
                this.context.setLineDash(style);
            }
            this.context.strokeStyle = ccr(color);
            this.context.lineWidth = width;
            if (this.context.lineWidth < 1) {
                this.context.lineWidth = 1;
            }
            this.context.strokeRect(Math.round(left * this.sfX), Math.round(top * this.sfY), Math.round(w * this.sfX), Math.round(h * this.sfY));
            if (style != 0) {
                this.context.setLineDash([]);
            }
        };
        /*
        * 绘制圆角矩形
        * color:颜色
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        * cornerRadius:圆角度数
        */
        drr(color, width, style, left, top, right, bottom, cornerRadius) {
            if (cornerRadius > 0) {
                width = Math.min(this.sfX, this.sfY) * width;
                if (style != 0) {
                    this.context.setLineDash(style);
                }
                this.context.strokeStyle = ccr(color);
                this.context.lineWidth = width;
                if (this.context.lineWidth < 1) {
                    this.context.lineWidth = 1;
                }
                let corner = cornerRadius * Math.min(this.sfX, this.sfY);
                let w = Math.round((right - left) * this.sfX);
                let h = Math.round((bottom - top) * this.sfY);
                let x = left * this.sfX;
                let y = top * this.sfY;
                this.context.beginPath();
                this.context.moveTo(x + corner, y);
                this.context.arcTo(x + w, y, x + w, y + h, corner);
                this.context.arcTo(x + w, y + h, x, y + h, corner);
                this.context.arcTo(x, y + h, x, y, corner);
                this.context.arcTo(x, y, x + corner, y, corner);
                this.context.stroke();
                if (style != 0) {
                    this.context.setLineDash([]);
                }
            } else {
                this.dr(color, width, style, left, top, right, bottom);
            }
        };
        /*
        * 绘制文字
        * text:文字
        * color:颜色
        * font:字体
        * x:横坐标
        * y:纵坐标
        */
        dt(text, color, font, x, y) {
            if (text && text.length != 0 && font) {
                let strs = font.split(',');
                let fontFamily = strs[0];
                if (fontFamily == "Default") {
                    fontFamily = this.systemFont;
                }
                let sFont = parseInt(strs[1]) + "px " + fontFamily;
                if (this.sfX != 1 || this.sfY != 1) {
                    sFont = parseInt(Math.min(this.sfX, this.sfY) * parseFloat(strs[1])) + "px " + fontFamily;
                }
                for (let i = 2; i < strs.length; i++) {
                    let iStr = strs[i].toLowerCase();
                    if (iStr == "bold" || iStr == "italic") {
                        sFont = iStr + " " + sFont;
                    }
                }
                this.context.font = sFont;
                this.context.fillStyle = ccr(color);
                this.context.textAlign = 'left';
                this.context.textBaseline = 'top';
                this.context.fillText(text, Math.round(x * this.sfX), Math.round(y * this.sfY));
            }
        };
        /*
        * 结束绘图
        */
        endPaint() {
            if(this.container){
                this.context.draw();
            }
        };
        /*
        * 填充路径
        * color:颜色
        */
        fillPath(color) {
            let fColor = ccr(color);
            if (this.context.fillStyle != fColor) {
                this.context.fillStyle = fColor;
            }
            this.context.fill();
        };
        /*
        * 填充矩形
        * color:颜色
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        */
        fr(color, left, top, right, bottom) {
            let w = right - left;
            let h = bottom - top;
            this.context.fillStyle = ccr(color);
            this.context.fillRect(Math.round(left * this.sfX), Math.round(top * this.sfY), Math.round(w * this.sfX), Math.round(h * this.sfY));
        };
        /*
        * 填充圆角矩形
        * color:颜色
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        * cornerRadius:圆角度数
        */
        frr(color, left, top, right, bottom, cornerRadius) {
            if (cornerRadius > 0) {
                let w = Math.round((right - left) * this.sfX);
                let h = Math.round((bottom - top) * this.sfY);
                let x = left * this.sfX;
                let y = top * this.sfY;
                let corner = cornerRadius * Math.min(this.sfX, this.sfY);
                this.context.beginPath();
                this.context.moveTo(x + corner, y);
                this.context.arcTo(x + w, y, x + w, y + h, corner);
                this.context.arcTo(x + w, y + h, x, y + h, corner);
                this.context.arcTo(x, y + h, x, y, corner);
                this.context.arcTo(x, y, x + corner, y, corner);
                this.context.fillStyle = ccr(color);
                this.context.fill();
            } else {
                this.fr(color, left, top, right, bottom);
            }
        };
        /*
        * 填充椭圆
        * color:颜色
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        */
        fe(color, left, top, right, bottom) {
            let w = right - left;
            let h = bottom - top;
            this.context.fillStyle = ccr(color);
            let centerX = (left + (right - left) / 2) * this.sfX;
            let centerY = (top + (bottom - top) / 2) * this.sfY;
            if (this.context.ellipse) {
                this.context.beginPath();
                this.context.ellipse(centerX, centerY, (w / 2) * this.sfX, (h / 2) * this.sfY, 0, 0, Math.PI * 2);
                this.context.fill();
            } else {
                let radius = Math.max(w, h) / 2;
                if(radius < 1){
                    radius = 1;
                }
                this.context.save();
                this.context.translate(centerX, centerY);
                if(radius > 1){
                    if (w > h) {
                        this.context.scale(1, h / w);
                    } else if (w < h) {
                        this.context.scale(w / h, 1);
                    }
                }
                this.context.beginPath();
                this.context.arc(0, 0, radius, 0, 2 * Math.PI, false);
                this.context.fill();
                this.context.restore();
            }
        };
        /*
        * 填充多边形
        * color:颜色
        * width:宽度
        * style:样式
        */
        fpg(color, apt) {
            if(apt.length > 1){
                this.context.beginPath();
                for(let i = 0; i < apt.length; i++){
                    let x = apt[i].x;
                    let y = apt[i].y;
                    if (this.sfX != 1 || this.sfY != 1){
                        x = this.sfX * x;
                        y = this.sfY * y;
                    }
                    if (i == 0){
                        this.context.moveTo(Math.round(x), Math.round(y));
                    }else{
                        this.context.lineTo(Math.round(x), Math.round(y));
                    }
                }
                this.context.fillStyle = ccr(color);
                this.context.closePath();
                this.context.fill();
            }
        };
        /*
        * 获取字体大小
        * text:文字
        * font:字体
        */
        ts(text, font) {
            if (text && text.length != 0 && font) {
                let strs = font.split(',');
                let fontFamily = strs[0];
                if (fontFamily == "Default") {
                    fontFamily = this.systemFont;
                }
                let sFont = parseInt(strs[1]) + "px " + fontFamily;
                for (let i = 2; i < strs.length; i++) {
                    let iStr = strs[i].toLowerCase();
                    if (iStr == "bold" || iStr == "italic") {
                        sFont = iStr + " " + sFont;
                    }
                }
                this.context.font = sFont;
                this.context.textAlign = 'left';
                this.context.textBaseline = 'top';
                let metrics = this.context.measureText(text);
                if(this.container){
                    return new FS(metrics.width, parseInt(strs[1]));
                }else{
                    let actualHeight = metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
                    if(!actualHeight || actualHeight <= 0){
                        return new FS(metrics.width, parseInt(strs[1]));
                    }else{
                        let tSize = new FS(metrics.width, actualHeight);
                        return tSize;
                    }
                }
            } else {
                return new FS(0, 0);
            }
        };
        /*
        * 保存状态
        */
        save() {
            this.context.save();
        };
        /*
        * 恢复状态
        */
        restore() {
            this.context.restore();
        };
        /*
        * 绘制文字，超过范围的内容用...表示
        * text:文字
        * color:颜色
        * font:字体
        * left:左侧坐标
        * top:上方坐标
        * right:右侧坐标
        * bottom:下方坐标
        */
        dtae(text, color, font, left, top, right, bottom) {
            if (text && text.length != 0) {
                let tSize = this.ts(text, font);
                if (tSize.cx < right - left) {
                    this.dt(text, color, font, left, top);
                } else {
                    if (tSize.cx > 0) {
                        let subLen = 3;
                        while (true) {
                            let newLen = text.length - subLen;
                            if (newLen > 0) {
                                let newText = text.substring(0, newLen) + "...";
                                tSize = this.ts(newText, font);
                                if (tSize.cx < right - left) {
                                    this.dt(newText, color, font, left, top);
                                    break;
                                } else {
                                    subLen += 3;
                                }
                            } else {
                                break;
                            }
                        }
                    }
                }
            }
        };
    };
        
    /*
    * 基础视图
    */
    class FCView {
        // 构造函数
        constructor() {
            this.allowDragScroll = false; //是否允许拖动滚动
            this.backColor = null; //背景色
            this.borderColor = null; //边线色
            this.clipRect = null; //裁剪区域
            this.cornerRadius = 0; //圆角
            this.dock = "none"; //悬浮状态
            this.downScrollHButton = false; //是否按下横向滚动条
            this.downScrollVButton = false; //是否按下纵向滚动条
            this.exAttributes = new Map(); //额外属性
            this.enabled = true; //是否可用
            this.font = "Default,12"; //字体
            this.hoveredColor = null; //鼠标悬停时的颜色
            this.input = null; //包含的原生组件
            this.location = new FP(0, 0); //坐标
            this.maximumSize = new FS(0, 0); //大小
            this.paint = null; //绘图对象
            this.parent = null; //父视图
            this.pushedColor = "rgb(200,200,200)"; //鼠标按下时的颜色
            this.scrollV = 0; //纵向滚动
            this.scrollH = 0; //横向滚动
            this.scrollSize = 8; //滚动条的大小
            this.showHScrollBar = false; //是否显示横向滚动条
            this.showVScrollBar = false; //是否显示纵向滚动条
            this.scrollBarColor = "rgb(200,200,200)"; //滚动条的颜色
            this.scrollBarHoveredColor = "rgb(42,138,195)"; //滚动条悬停的颜色
            this.size = new FS(0, 0); //大小
            this.startScrollH = 0; //开始滚动的值
            this.startScrollV = 0; //结束滚动的值
            this.startPoint = new FP(); //起始点
            this.startRect = new FR(); //移动开始时的视图矩形
            this.text = null; //文字
            this.textColor = null; //前景色
            this.touchDownTime = 0; //鼠标按下的时间
            this.views = new Array(); //子视图
            this.viewName = null; //名称
            this.visible = true; //可见性
        };
    };

    /*
    * 表格列
    */
    class FCGridColumn {
        constructor() {
            this.backColor = "rgb(200,200,200)"; //背景色
            this.borderColor = "rgb(150,150,150)"; //边线颜色
            this.bounds = new FR(); //区域
            this.font = "Default,12"; //字体
            this.frozen = false; //是否冻结
            this.index = -1; //索引
            this.sort = "none"; //排序模式
            this.text = ""; //文字
            this.textColor = "rgb(50,50,50)"; //文字颜色
            this.visible = true; //是否可见
            this.width = 120; //宽度
            this.widthStr = ""; //宽度字符串
        }
    };

    /*
    * 表格单元格
    */
    class FCGridCell {
        constructor() {
            this.backColor = "rgb(255,255,255)"; //背景色
            this.borderColor = "rgb(150,150,150)"; //边线颜色
            this.column = null; //所在列
            this.font = "Default,12"; //字体
            this.textColor = "rgb(0,0,0)"; //文字颜色
            this.value = null; //值
        }
    };

    /*
    * 表格行
    */
    class FCGridRow {
        constructor() {
            this.cells = new Array(); //单元格
            this.index = -1; //行的索引
            this.selected = false; //是否选中
            this.visible = true; //是否可见
        }
    };

    /*
    * 表格
    */
    class FCGrid extends FCView {
        // 构造函数
        constructor() {
            super();
            super.allowDragScroll = true; //是否允许拖动滚动
            this.columns = new Array(); //列
            this.headerHeight = 30; //头部高度
            this.rows = new Array(); //行
            this.rowHeight = 30; //行高
            super.showHScrollBar = true; //是否显示横向滚动条
            super.showVScrollBar = true; //是否显示横向滚动条
            this.selectedRowColor = "rgb(125,125,125)"; //选中行的颜色
            super.viewType = "grid"; //类型
        }
    };

    /*
    * 添加顶层视图
    * view:视图
    * paint:绘图对象
    */
    let addView = function (view, paint) {
        view.paint = paint;
        paint.views.push(view);
    };
    /*
    * 获取点击位置
    * evt:事件
    * canvas:图层
    * ratio:比例
    */
    let gtp = function (evt, canvas, paint) {
        let style = window.getComputedStyle(canvas, null);
        //宽高
        let cssWidth = parseFloat(style["width"]);
        let cssHeight = parseFloat(style["height"]);
        //各个方向的边框长度
        let borderLeft = parseFloat(style["border-left-width"]);
        let borderTop = parseFloat(style["border-top-width"]);
        let paddingLeft = parseFloat(style["padding-left"]);
        let paddingTop = parseFloat(style["padding-top"]);

        let scaleX = canvas.width / cssWidth; // 水平方向的缩放因子
        let scaleY = canvas.height / cssHeight; // 垂直方向的缩放因子
        let x = evt.clientX;
        let y = evt.clientY;

        let rect = canvas.getBoundingClientRect();
        x -= (rect.left + borderLeft + paddingLeft); // 去除 borderLeft paddingLeft 后的坐标
        y -= (rect.top + borderTop + paddingTop); // 去除 borderLeft paddingLeft 后的坐标

        x *= scaleX; // 修正水平方向的坐标
        y *= scaleY; // 修正垂直方向的坐标
        x /= paint.ratio;
        y /= paint.ratio;
        x /= paint.sfX;
        y /= paint.sfY;
        return { x, y };
    };

    /*
    * 重绘视图
    * views:视图集合
    * paint:绘图对象
    * rect:区域
    */
    let renderViews = function (views, paint, rect) {
        let viewsSize = views.length;
        for (let i = 0; i < viewsSize; i++) {
            let view = views[i];
            let dr = new FR(0, 0, view.size.cx, view.size.cy);
            if (paint.onPaint) {
                paint.onPaint(view, paint, dr);
            } 
            if (paint.onPaintBorder) {
                paint.onPaintBorder(view, paint, dr);
            } 
        }
    };

    /*
    * 全局刷新方法
    * paint:绘图对象
    */
    let iv = function (paint) {
        let drawViews = paint.views;
        paint.beginPaint(null);
        let dr = new FR(0, 0, (paint.canvas.width / paint.ratio / paint.sfX), (paint.canvas.height / paint.ratio / paint.sfY));
        renderViews(drawViews, paint, dr);
        paint.endPaint();
    };

    /*
    * 刷新视图方法
    * view:视图
    */
    let ivv = function (view) {
        iv(view.paint);
    };
        
    /*
    * 更新布局状态
    * views:视图集合
    */
    let uvd = function (views) {
        for (let i = 0; i < views.length; i++) {
            let view = views[i];
            if (view.dock == "fill") {
                let paint = view.paint;
                view.size = new FS((paint.canvas.width / paint.ratio / paint.sfX), (paint.canvas.height / paint.ratio / paint.sfY));
            }
            if (view.views) {
                uvd(view.views);
            }
        }
    };

    /*
    * 添加鼠标按下的方法
    * canvas:图层
    * callBack:回调函数
    */
    let amde = function (canvas, paint, callBack) {
        canvas.onmousedown = function (evt) {
            if (!paint.isMobile) {
                let mp = gtp(evt, canvas, paint);
                paint.cancelClick = false;
                paint.touchDownPoint = mp;
                paint.touchDownView = gList;
                if (paint.touchDownView) {
                    paint.focusedView = paint.touchDownView;
                    let cmp = new FP(mp.x, mp.y);
                    if (callBack) {
                        if (evt.button == 2) {
                            callBack(paint.touchDownView, cmp, 2, 1, 0);
                        } else {
                            callBack(paint.touchDownView, cmp, 1, 1, 0);
                        }
                    } 
                }
            }
        };
    };

    /*
    * 添加鼠标移动的方法
    * canvas:图层
    * callBack:回调函数
    */
    let amme = function (canvas, paint, callBack) {
        canvas.onmousemove = function (evt) {
            if (evt.buttons == 0) {
                paint.touchDownView = null;
            }
            if (!paint.isMobile) {
                let mp = gtp(evt, canvas, paint);
                if (paint.touchDownView) {
                    paint.touchMoveView = paint.touchDownView;
                    let cmp = new FP(mp.x, mp.y);
                    if (callBack) {
                        callBack(paint.touchDownView, cmp, 1, 1, 0);
                    } 
                }
                else {
                    let view = gList;
                    let cmp = new FP(mp.x, mp.y);
                    if (view) {
                        oldMouseMoveView = paint.touchMoveView
                        paint.touchMoveView = view;
                        if (oldMouseMoveView && oldMouseMoveView != view) {
                            ivv(oldMouseMoveView);
                        }
                        if (callBack) {
                            callBack(view, cmp, 0, 0, 0);
                        } 
                    }
                }
            }
        };
    };

    /*
    * 添加鼠标滚动的方法
    * canvas:图层
    * callBack:回调函数
    */
    let amwe = function (canvas, paint, callBack) {
        canvas.addEventListener("DOMMouseScroll", function (evt) {
            if (!paint.isMobile) {
                let mp = gtp(evt, canvas, paint);
                let view = gList;
                if (view) {
                    let cmp = new FP(mp.x, mp.y);
                    let delta = evt.detail;
                    if (callBack) {
                        callBack(view, cmp, 0, 0, delta);
                    } 
                }
                if (view && view.allowDragScroll) {
                    evt.preventDefault && evt.preventDefault();
                    evt.returnValue = false;
                    evt.stopPropagation && evt.stopPropagation();
                }
            }
            return false;
        }, false);
        //图层鼠标移动事件
        canvas.onmousewheel = function (evt) {
            if (!paint.isMobile) {
                let mp = gtp(evt, canvas, paint);
                let view = gList;
                if (view) {
                    let cmp = new FP(mp.x, mp.y);
                    let delta = evt.deltaY;
                    if (callBack) {
                        callBack(view, cmp, 0, 0, delta);
                    } 
                }
                if (view && view.allowDragScroll) {
                    evt.preventDefault && evt.preventDefault();
                    evt.returnValue = false;
                    evt.stopPropagation && evt.stopPropagation();
                }
            }
            return false;
        };
    };

    /*
    * 添加鼠标抬起的方法
    * canvas:图层
    * callBack:回调函数
    */
    let amue = function (canvas, paint, callBack, clickCallBack) {
        canvas.onmouseup = function (evt) {
            if (!paint.isMobile) {
                let mp = gtp(evt, canvas, paint);
                if (paint.touchDownView) {
                    let cmp = new FP(mp.x, mp.y);
                    let view = gList;
                    if (view != null && view == paint.touchDownView) {
                        if (!paint.cancelClick) {
                            if (clickCallBack) {
                                clickCallBack(paint.touchDownView, true, cmp, false, cmp, 1);
                            } 
                        }
                    }
                    if (paint.touchDownView) {
                        let touchDownView = paint.touchDownView;
                        paint.touchDownView = null;
                        paint.touchMoveView = null;
                        if (callBack) {
                            callBack(touchDownView, cmp, 1, 1, 0);
                        }
                    }
                }
            }
        };
    };

    /*
    * 添加触摸开始的方法
    * canvas:图层
    * callBack:回调函数
    */
    let atbe = function (canvas, paint, callBack) {
        /*
        * 触摸开始方法
        * evt: 事件参数
        */
        canvas.ontouchstart = function (evt) {
            if (paint.isMobile) {
                paint.cancelClick = false;
                let mp = gtp(evt.touches[0], canvas, paint);
                paint.touchDownPoint = new FP(mp.x, mp.y);
                paint.touchDownView = gList;
                if (paint.touchDownView) {
                    paint.focusedView = paint.touchDownView;
                    paint.firstTouch = false;
                    paint.secondTouch = false;
                    paint.tpf = new FP();
                    paint.tsp = new FP();
                    if (evt.touches.length >= 1) {
                        paint.firstTouch = true;
                        paint.tpf = gtp(evt.touches[0], canvas, paint);
                    }
                    if (evt.touches.length >= 2) {
                        paint.secondTouch = true;
                        paint.tsp = gtp(evt.touches[1], canvas, paint);
                    }
                    if (callBack) {
                        callBack(paint.touchDownView, paint.firstTouch, paint.tpf, paint.secondTouch, paint.tsp);
                    } 
                }
            }
        };
    };

    /*
    * 添加触摸移动的方法
    * canvas:图层
    * callBack:回调函数
    */
    let atme = function (canvas, paint, callBack) {
        canvas.ontouchmove = function (evt) {
            if (paint.isMobile) {
                if (paint.touchDownView) {
                    paint.firstTouch = false;
                    paint.secondTouch = false;
                    paint.tpf = new FP();
                    paint.tsp = new FP();
                    let mp = gtp(evt.touches[0], canvas, paint);
                    if (evt.touches.length >= 1) {
                        paint.firstTouch = true;
                        paint.tpf = gtp(evt.touches[0], canvas, paint);
                    }
                    if (evt.touches.length >= 2) {
                        paint.secondTouch = true;
                        paint.tsp = gtp(evt.touches[1], canvas, paint);
                    }
                    if (callBack) {
                        callBack(paint.touchDownView, paint.firstTouch, paint.tpf, paint.secondTouch, paint.tsp);
                    } 
                    paint.touchDownPoint = mp;
                    if (paint.touchDownView && paint.touchDownView.allowDragScroll) {
                        evt.preventDefault && evt.preventDefault();
                        evt.returnValue = false;
                        evt.stopPropagation && evt.stopPropagation();
                    }
                }
            }
            return false;
        };
    };

    /*
    * 添加触摸结束的方法
    * canvas:图层
    * callBack:回调函数
    */
    let atee = function (canvas, paint, callBack, clickCallBack) {
        canvas.ontouchend = function (evt) {
            if (paint.isMobile) {
                if (paint.touchDownView) {
                    let touchDownView = paint.touchDownView;
                    let mp = paint.touchDownPoint;
                    let view = gList;
                    if (view != null && view == paint.touchDownView) {
                        let cmp = new FP(mp.x, mp.y);
                        if (clickCallBack) {
                            clickCallBack(paint.touchDownView, true, cmp, false, cmp, 1);
                        } 
                    }
                    paint.touchDownView = null;
                    if (callBack) {
                        callBack(touchDownView, paint.firstTouch, paint.tpf, paint.secondTouch, paint.tsp);
                    } 
                }
            }
        };
    };

    /*
    * 绘制表格
    * grid:表格
    * paint:绘图对象
    * clipRect:裁剪区域
    */
    let drawGrid = function (grid, paint, clipRect) {
        let cTop = -grid.scrollV + grid.headerHeight;
        //绘制行
        let colLeft = 0;
        for (let i = 0; i < grid.columns.length; i++) {
            if (grid.columns[i].widthStr.length > 0) {
                let newWidthStr = grid.columns[i].widthStr.replace("%", "");
                grid.columns[i].width = Number(newWidthStr) * grid.size.cx / 100;
            }
            let colRect = new FR(colLeft, 0, colLeft + grid.columns[i].width, grid.headerHeight);
            grid.columns[i].bounds = colRect;
            grid.columns[i].index = i;
            colLeft += grid.columns[i].width;
        }
        for (let i = 0; i < grid.rows.length; i++) {
            let row = grid.rows[i];
            row.index = i;
            if (row.visible) {
                let rowHeight = grid.rowHeight;
                if (i < 2) {
                    rowHeight = 50;
                }
                let rTop = cTop, rBottom = cTop + rowHeight;
                if (rBottom >= 0 && cTop <= grid.size.cy) {
                    for (let j = 0; j < row.cells.length; j++) {
                        let c = row.cells[j];
                        let gridColumn = c.column;
                        if (!gridColumn) {
                            gridColumn = grid.columns[j];
                        }
                        if (gridColumn.visible) {
                            if (!gridColumn.frozen) {
                                let cellWidth = gridColumn.width;
                                let cellHeight = rowHeight;
                                let cRect = new FR(gridColumn.bounds.l - grid.scrollH, rTop, gridColumn.bounds.l + cellWidth - grid.scrollH, rTop + cellHeight);
                                if (cRect.r >= 0 && cRect.l < grid.size.cx) {
                                    if (paint.onPaintGridCell) {
                                        paint.onPaintGridCell(grid, row, gridColumn, c, paint, cRect.l, cRect.t, cRect.r, cRect.b);
                                    } 
                                }
                            }
                        }
                    }
                }
                if (cTop > grid.size.cy) {
                    break;
                }
                cTop += rowHeight;
            }
        }
    };

    /*
    * 绘制表格的滚动条
    * grid:表格
    * paint:绘图对象
    * clipRect:裁剪区域
    */
    let drawGridScrollBar = function (grid, paint, clipRect) {
        if (grid.headerHeight > 0) {
            let cLeft = -grid.scrollH;
            //绘制列
            for (let i = 0; i < grid.columns.length; i++) {
                let gridColumn = grid.columns[i];
                if (grid.columns[i].visible) {
                    if (!gridColumn.frozen) {
                        if (paint.onPaintGridColumn) {
                            paint.onPaintGridColumn(grid, grid.columns[i], paint, cLeft, 0, cLeft + gridColumn.width, grid.headerHeight);
                        } 
                    }
                    cLeft += gridColumn.width;
                }
            }
        }
        if (paint.isMobile) {
            if (paint.touchDownView == grid) {
            } else if (g_dragScrollView_Grid == grid && g_scrollAddSpeed_Grid != 0) {
            } else {
                return;
            }
        }
        if (grid.showHScrollBar) {
            let contentWidth = getGridContentWidth(grid);
            if (contentWidth > 0 && contentWidth > grid.size.cx) {
                let sLeft = grid.scrollH / contentWidth * grid.size.cx;
                let sRight = (grid.scrollH + grid.size.cx) / contentWidth * grid.size.cx;
                if (sRight - sLeft < grid.scrollSize) {
                    sRight = sLeft + grid.scrollSize;
                }
                if (paint.touchMoveView == grid && (grid.hoverScrollHButton || grid.downScrollHButton)) {
                    paint.fr(grid.scrollBarHoveredColor, sLeft, grid.size.cy - grid.scrollSize, sRight, grid.size.cy);
                } else {
                    paint.fr(grid.scrollBarColor, sLeft, grid.size.cy - grid.scrollSize, sRight, grid.size.cy);
                }
            }
        }
        if (grid.showVScrollBar) {
            let contentHeight = getGridContentHeight(grid);
            if (contentHeight > 0 && contentHeight > grid.size.cy - grid.headerHeight) {
                let sTop = grid.headerHeight + grid.scrollV / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize);
                let sBottom = sTop + ((grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize);
                if (sBottom - sTop < grid.scrollSize) {
                    sBottom = sTop + grid.scrollSize;
                }
                if (paint.touchMoveView == grid && (grid.hoverScrollVButton || grid.downScrollVButton)) {
                    paint.fr(grid.scrollBarHoveredColor, grid.size.cx - grid.scrollSize, sTop, grid.size.cx, sBottom);
                } else {
                    paint.fr(grid.scrollBarColor, grid.size.cx - grid.scrollSize, sTop, grid.size.cx, sBottom);
                }
            }
        }
    };

    /*
    * 获取内容的宽度
    * grid:表格
    */
    let getGridContentWidth = function (grid) {
        return grid.size.cx;
    };

    /*
    * 获取内容的高度
    * grid:表格
    */
    let getGridContentHeight = function (grid) {
        let cHeight = 0;
        for (let i = 0; i < grid.rows.length; i++) {
            if (grid.rows[i].visible) {
                cHeight += grid.rowHeight;
            }
        }
        return cHeight;
    };

    /*
    * 表格的鼠标移动方法
    * grid: 表格
    * firstTouch:是否第一次触摸
    * firstPoint:第一次触摸的坐标
    * secondTouch:是否第二次触摸
    * secondPoint:第二次触摸的坐标
    */
    let touchMoveGrid = function (grid, firstTouch, firstPoint, secondTouch, secondPoint) {
        grid.hoverScrollHButton = false;
        grid.hoverScrollVButton = false;
        let mp = firstPoint;
        if (firstTouch) {   
            if (grid.showHScrollBar || grid.showVScrollBar) {
                if (grid.downScrollHButton) {
                    let contentWidth = getGridContentWidth(grid);
                    let subX = (mp.x - grid.startPoint.x) / grid.size.cx * contentWidth;
                    let newScrollH = grid.startScrollH + subX;
                    if (newScrollH < 0) {
                        newScrollH = 0;
                    } else if (newScrollH > contentWidth - grid.size.cx) {
                        newScrollH = contentWidth - grid.size.cx;
                    }
                    grid.scrollH = newScrollH;
                    grid.paint.cancelClick = true;
                    return;

                } else if (grid.downScrollVButton) {
                    let contentHeight = getGridContentHeight(grid);
                    let subY = (mp.y - grid.startPoint.y) / (grid.size.cy - grid.headerHeight - grid.scrollSize) * contentHeight;
                    let newScrollV = grid.startScrollV + subY;
                    if (newScrollV < 0) {
                        newScrollV = 0;
                    } else if (newScrollV > contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize)) {
                        newScrollV = contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize);
                    }
                    grid.scrollV = newScrollV;
                    grid.paint.cancelClick = true;
                    return;
                }
            }
            if (grid.allowDragScroll) {
                let contentWidth = getGridContentWidth(grid);
                if (contentWidth > grid.size.cx - grid.scrollSize) {
                    let subX = grid.startPoint.x - mp.x;
                    let newScrollH = grid.startScrollH + subX;
                    if (newScrollH < 0) {
                        newScrollH = 0;
                    } else if (newScrollH > contentWidth - grid.size.cx) {
                        newScrollH = contentWidth - grid.size.cx;
                    }
                    grid.scrollH = newScrollH;
                    if (Math.abs(subX) > 5) {
                        grid.paint.cancelClick = true;
                    }
                }
                let contentHeight = getGridContentHeight(grid);
                if (contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize) {
                    let subY = grid.startPoint.y - mp.y;
                    let newScrollV = grid.startScrollV + subY;
                    if (newScrollV < 0) {
                        newScrollV = 0;
                    } else if (newScrollV > contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize)) {
                        newScrollV = contentHeight - (grid.size.cy - grid.headerHeight - grid.scrollSize);
                    }
                    grid.scrollV = newScrollV;
                    if (Math.abs(subY) > 5) {
                        grid.paint.cancelClick = true;
                    }
                }
            }
        } else {
            if (grid.showHScrollBar) {
                let contentWidth = getGridContentWidth(grid);
                if (contentWidth > 0 && contentWidth > grid.size.cx - grid.scrollSize) {
                    let sLeft = grid.scrollH / contentWidth * grid.size.cx;
                    let sRight = (grid.scrollH + grid.size.cx) / contentWidth * grid.size.cx;
                    if (sRight - sLeft < grid.scrollSize) {
                        sRight = sLeft + grid.scrollSize;
                    }
                    if (mp.x >= sLeft && mp.x <= sRight && mp.y >= grid.size.cy - grid.scrollSize && mp.y <= grid.size.cy) {
                        grid.hoverScrollHButton = true;
                        return;
                    } else {
                        grid.hoverScrollHButton = false;
                    }
                }
            }
            if (grid.showVScrollBar) {
                let contentHeight = getGridContentHeight(grid);
                if (contentHeight > 0 && contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize) {
                    let sTop = grid.headerHeight + grid.scrollV / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize);
                    let sBottom = grid.headerHeight + (grid.scrollV + (grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize);
                    if (sBottom - sTop < grid.scrollSize) {
                        sBottom = sTop + grid.scrollSize;
                    }
                    if (mp.x >= grid.size.cx - grid.scrollSize && mp.x <= grid.size.cx && mp.y >= sTop && mp.y <= sBottom) {
                        grid.hoverScrollVButton = true;
                        return;
                    } else {
                        grid.hoverScrollVButton = false;
                    }
                }
            }
        }
    };
        
    /*
    * 表格的鼠标按下方法
    * grid: 表格
    * firstTouch:是否第一次触摸
    * firstPoint:第一次触摸的坐标
    * secondTouch:是否第二次触摸
    * secondPoint:第二次触摸的坐标
    * clicks:点击次数
    */
    let touchDownGrid = function (grid, firstTouch, firstPoint, secondTouch, secondPoint, clicks) {
        let mp = firstPoint;
        grid.touchDownTime = new Date().getTime()
        grid.startPoint = mp;
        grid.downScrollHButton = false;
        grid.downScrollVButton = false;
        grid.hoverScrollHButton = false;
        grid.hoverScrollVButton = false;
        g_dragScrollView_Grid = null;
        g_scrollAddSpeed_Grid = 0;
        g_scrollDirection_Grid = 0;
        if (grid.showHScrollBar) {
            let contentWidth = getGridContentWidth(grid);
            if (contentWidth > 0 && contentWidth > grid.size.cx - grid.scrollSize) {
                let sLeft = grid.scrollH / contentWidth * grid.size.cx;
                let sRight = (grid.scrollH + grid.size.cx) / contentWidth * grid.size.cx;
                if (sRight - sLeft < grid.scrollSize) {
                    sRight = sLeft + grid.scrollSize;
                }
                if (mp.x >= sLeft && mp.x <= sRight && mp.y >= grid.size.cy - grid.scrollSize && mp.y <= grid.size.cy) {
                    grid.downScrollHButton = true;
                    grid.startScrollH = grid.scrollH;
                    return;
                }
            }
        }
        if (grid.showVScrollBar) {
            let contentHeight = getGridContentHeight(grid);
            if (contentHeight > 0 && contentHeight > grid.size.cy - grid.headerHeight - grid.scrollSize) {
                let sTop = grid.headerHeight + grid.scrollV / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize);
                let sBottom = grid.headerHeight + (grid.scrollV + (grid.size.cy - grid.headerHeight - grid.scrollSize)) / contentHeight * (grid.size.cy - grid.headerHeight - grid.scrollSize);
                if (sBottom - sTop < grid.scrollSize) {
                    sBottom = sTop + grid.scrollSize;
                }
                if (mp.x >= grid.size.cx - grid.scrollSize && mp.x <= grid.size.cx && mp.y >= sTop && mp.y <= sBottom) {
                    grid.downScrollVButton = true;
                    grid.startScrollV = grid.scrollV;
                    return;
                }
            }
        }
        if (grid.allowDragScroll) {
            grid.startScrollH = grid.scrollH;
            grid.startScrollV = grid.scrollV;
        }
        let colLeft = 0;
        for (let i = 0; i < grid.columns.length; i++) {
            let colRect = new FR(colLeft, 0, colLeft + grid.columns[i].width, grid.headerHeight);
            grid.columns[i].bounds = colRect;
            grid.columns[i].index = i;
            colLeft += grid.columns[i].width;
        }
    };

    let g_dragScrollView_Grid = null;//正在滚动的表格
    let g_scrollAddSpeed_Grid = 0;//滚动加速
    let g_scrollDirection_Grid = 0; //滚动方向

    /*
    * 检查拖动滚动
    */
    let checkGridDragScroll = function () {
        if (g_dragScrollView_Grid) {
            let sub = parseInt(g_scrollAddSpeed_Grid / 10);
            if (sub == 0 && g_scrollAddSpeed_Grid > 1) {
                sub = 1;
            } else if (sub == 0 && g_scrollAddSpeed_Grid < -1) {
                sub = -1;
            }
            g_scrollAddSpeed_Grid -= sub;
            if (sub == 0) {
                let viewCache = g_dragScrollView_Grid;
                g_dragScrollView_Grid = null;
                g_scrollAddSpeed_Grid = 0;
                if (viewCache.paint) {
                    ivv(viewCache);
                }
            } else {
                let oldScrollV = parseInt(g_dragScrollView_Grid.scrollV + g_scrollAddSpeed_Grid);
                let oldScrollH = parseInt(g_dragScrollView_Grid.scrollH + g_scrollAddSpeed_Grid);
                if (g_scrollDirection_Grid == 0) {
                    let contentHeight = getGridContentHeight(g_dragScrollView_Grid);
                    if (contentHeight < g_dragScrollView_Grid.size.cy - g_dragScrollView_Grid.scrollSize) {
                        g_dragScrollView_Grid.scrollV = 0;
                    } else {
                        if (oldScrollV < 0) {
                            oldScrollV = 0;
                        } else if (oldScrollV > contentHeight - g_dragScrollView_Grid.size.cy + g_dragScrollView_Grid.headerHeight + g_dragScrollView_Grid.scrollSize) {
                            oldScrollV = contentHeight - g_dragScrollView_Grid.size.cy + g_dragScrollView_Grid.headerHeight + g_dragScrollView_Grid.scrollSize;
                        }
                        g_dragScrollView_Grid.scrollV = oldScrollV;
                    }
                } else {
                    let contentWidth = getGridContentWidth(g_dragScrollView_Grid);
                    if (contentWidth < g_dragScrollView_Grid.size.cx - g_dragScrollView_Grid.headerHeight - g_dragScrollView_Grid.scrollSize) {
                        g_dragScrollView_Grid.scrollH = 0;
                    } else {
                        if (oldScrollH < 0) {
                            oldScrollH = 0;
                        } else if (oldScrollH > contentWidth - g_dragScrollView_Grid.size.cx) {
                            oldScrollH = contentWidth - g_dragScrollView_Grid.size.cx;
                        }
                        g_dragScrollView_Grid.scrollH = oldScrollH;
                    }
                }
                if (g_dragScrollView_Grid.paint) {
                    ivv(g_dragScrollView_Grid);
                }
            }
        }
    };

    /*
    * 表格的鼠标抬起方法
    * grid: 表格
    * firstTouch:是否第一次触摸
    * firstPoint:第一次触摸的坐标
    * secondTouch:是否第二次触摸
    * secondPoint:第二次触摸的坐标
    * clicks:点击次数
    */
    let touchUpGrid = function (grid, firstTouch, firstPoint, secondTouch, secondPoint, clicks) {
        grid.hoverScrollHButton = false;
        grid.hoverScrollVButton = false;
        if (firstTouch && firstPoint && grid.startPoint && !grid.downScrollHButton && !grid.downScrollVButton) {
            if (grid.allowDragScroll) {
                let touchUpTime = new Date().getTime();
                let diff = touchUpTime - grid.touchDownTime;
                //加速滚动
                if (diff < 250) {
                    let sub1 = 100 * ((Math.abs(firstPoint.y - grid.startPoint.y)) / 20) / diff * 10;
                    let sub2 = 100 * ((Math.abs(firstPoint.x - grid.startPoint.x)) / 20) / diff * 10;
                    if ("A:" + sub1 != "A:NaN" && "A:" + sub2 != "A:NaN") {
                        if (Math.abs(sub1) > Math.abs(sub2)) {
                            if (firstPoint.y < grid.startPoint.y) {
                                g_scrollAddSpeed_Grid += sub1;
                            } else {
                                g_scrollAddSpeed_Grid -= sub1;
                            }
                            g_scrollDirection_Grid = 0;
                        } else {
                            if (firstPoint.x < grid.startPoint.x) {
                                g_scrollAddSpeed_Grid += sub2;
                            } else {
                                g_scrollAddSpeed_Grid -= sub2;
                            }
                            g_scrollDirection_Grid = 1;
                        }
                        if (Math.abs(g_scrollAddSpeed_Grid) > 0) {
                            grid.paint.cancelClick = true;
                        }
                        g_dragScrollView_Grid = grid;
                    } 
                }
            }
        }
        grid.downScrollHButton = false;
        grid.downScrollVButton = false;
        if (grid.paint.cancelClick) {
            return;
        }
        let cTop = -grid.scrollV + grid.headerHeight;
        //绘制行
        let colLeft = 0;
        for (let i = 0; i < grid.columns.length; i++) {
            let colRect = new FR(colLeft, 0, colLeft + grid.columns[i].width, grid.headerHeight);
            grid.columns[i].bounds = colRect;
            grid.columns[i].index = i;
            colLeft += grid.columns[i].width;
        }
        if (grid.headerHeight > 0 && firstPoint.y <= grid.headerHeight) {
            let cLeft = 0;
            cLeft = -grid.scrollH;
            for (let i = 0; i < grid.columns.length; i++) {
                let gridColumn = grid.columns[i];
                if (grid.columns[i].visible) {
                    if (!gridColumn.frozen) {
                        if (firstPoint.x >= cLeft && firstPoint.x <= cLeft + gridColumn.width) {
                            if (grid.paint && grid.paint.onClickGridColumn) {
                                grid.paint.onClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks);
                            }
                            return;
                        }
                    }
                    cLeft += gridColumn.width;
                }
            }
        }
        for (let i = 0; i < grid.rows.length; i++) {
            let row = grid.rows[i];
            if (row.visible) {
                let rowHeight = grid.rowHeight;
                if (i < 2) {
                    rowHeight = 50;
                }
                let rTop = cTop, rBottom = cTop + rowHeight;
                if (rBottom >= 0 && cTop <= grid.size.cy) {
                    for (let j = 0; j < row.cells.length; j++) {
                        let c = row.cells[j];
                        let gridColumn = c.column;
                        if (!gridColumn) {
                            gridColumn = grid.columns[j];
                        }
                        if (gridColumn.visible) {
                            if (!gridColumn.frozen) {
                                let cellWidth = gridColumn.width;
                                let cellHeight = rowHeight;
                                let cRect = new FR(gridColumn.bounds.l - grid.scrollH, rTop, gridColumn.bounds.l + cellWidth - grid.scrollH, rTop + cellHeight);
                                if (cRect.r >= 0 && cRect.l < grid.size.cx) {
                                    if (firstPoint.x >= cRect.l && firstPoint.x <= cRect.r && firstPoint.y >= cRect.t && firstPoint.y <= cRect.b) {
                                        if (grid.paint && grid.paint.onClickGridCell) {
                                            grid.paint.onClickGridCell(grid, row, gridColumn, c, firstTouch, firstPoint, secondTouch, secondPoint, clicks);
                                        }
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
                if (cTop > grid.size.cy) {
                    break;
                }
                cTop += rowHeight;
            }
        }
    };

    /*
    * 表格的鼠标滚轮方法
    * grid:表格
    * delta:滚轮值
    */
    let touchWheelGrid = function (grid, delta) {
        let oldScrollV = grid.scrollV;
        if (delta < 0) {
            oldScrollV -= 20;
        } else if (delta > 0) {
            oldScrollV += 20;
        }
        let contentHeight = getGridContentHeight(grid);
        if (contentHeight < grid.size.cy - grid.headerHeight - grid.scrollSize) {
            grid.scrollV = 0;
        } else {
            if (oldScrollV < 0) {
                oldScrollV = 0;
            } else if (oldScrollV > contentHeight - grid.size.cy + grid.headerHeight + grid.scrollSize) {
                oldScrollV = contentHeight - grid.size.cy + grid.headerHeight + grid.scrollSize;
            }
            grid.scrollV = oldScrollV;
        }
    };

    /*
    * 是否移动端
    */
    let isMobileMode = function () {
        let ua = navigator.userAgent;
        let ipad = ua.match(/(iPad).*OS\s([\d_]+)/),
            isIphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/),
            isAndroid = ua.match(/(Android)\s+([\d.]+)/),
            isMobile = isIphone || isAndroid;
        return isMobile;
    };

    /*
    * 缩放Canvas
    */
    let scaleCanvas = function (paint) {
        //缩放高清模式
        if (window.devicePixelRatio && !isMobileMode()) {
            let canvas = paint.canvas;
            canvas.style.width = canvas.width + 'px';
            canvas.style.height = canvas.height + 'px';
            canvas.height = canvas.height * window.devicePixelRatio;
            canvas.width = canvas.width * window.devicePixelRatio;
            let context = canvas.getContext("2d"); //绘图上下文
            context.scale(window.devicePixelRatio, window.devicePixelRatio);
            paint.ratio = window.devicePixelRatio;
        }
    }

    let canvas = document.getElementById("exampleCanvas"); //绘图区域
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
    let gt = new FCPaint(); //绘图对象
    gt.canvas = canvas;
    scaleCanvas(gt);
    //判断主题色
    gt.ds = "dark";
    //判断移动端
    gt.isMobile = isMobileMode();
    if (gt.isMobile) {
        gt.sfX = 2.5;
        gt.sfY = 2.5;
    }else{
        gt.ds = "light";
    }
    let gList = new FCGrid();
    gList.dock = "fill";
    addView(gList, gt);
    gList.backColor = "rgb(0,0,0)";
    gList.borderColor = null;
    gList.textColor = "rgb(255,255,255)";
    gList.scrollBarColor = "rgb(100,100,100)";
    gList.visible = true;
    gList.rowHeight = 80;
    gList.headerHeight = 50;
    if (gList.paint.ds == "dark") {
        gList.backColor = "rgb(0,0,0)";
        gList.borderColor = null;
        gList.textColor = "rgb(255,255,255)";
        gList.scrollBarColor = "rgb(100,100,100)";
    } else if (gList.paint.ds == "light") {
        gList.backColor = "rgb(230,230,230)";
        gList.borderColor = null;
        gList.textColor = "rgb(0,0,0)";
        gList.scrollBarColor = "rgb(200,200,200)";
    }
    let gColumn = new FCGridColumn();
    gColumn.text = "id";
    gColumn.widthStr = "100%";
    gList.columns.push(gColumn);
    gColumn.backColor = "rgb(0,0,0)";
    gColumn.borderColor = "rgb(100,100,100)";
    gColumn.textColor = "rgb(255,255,255)";
    let onMouseDown = function (view, mp, buttons, clicks, delta) {
        touchDownGrid(view, true, mp, false, mp, clicks);
        ivv(view);
    };
    let onMouseWheel = function (view, mp, buttons, clicks, delta) {
        replayTick = 0;
        tick = 0;
        clickIndex = -1;
        touchWheelGrid(view, delta);
        ivv(view);
    };
    let onTouchBegin = function (view, firstTouch, firstPoint, secondTouch, secondPoint) {
        touchDownGrid(view, firstTouch, firstPoint, secondTouch, secondPoint, 1);
        ivv(view);
    };
    let onTouchMove = function (view, firstTouch, firstPoint, secondTouch, secondPoint) {
        if(firstTouch){
            replayTick = 0;
            tick = 0;
            clickIndex = -1;
            touchMoveGrid(view, firstTouch, firstPoint, secondTouch, secondPoint);
            ivv(view);
        }
    };
    let onTouchEnd = function (view, firstTouch, firstPoint, secondTouch, secondPoint) {
        touchUpGrid(view, firstTouch, firstPoint, secondTouch, secondPoint, 1);
        ivv(view);
    };
    let buttonRects = [];
    let mouseMovePoint = new FP();
    let onMouseMove = function (view, mp, buttons, clicks, delta) {
        let firstTouch = false;
        mouseMovePoint = mp;
        if (buttons == 1) {
            firstTouch = true;
            replayTick = 0;
            tick = 0;
            clickIndex = -1;
        }  
        touchMoveGrid(view, firstTouch, mp, false, mp);
        ivv(view);
        let hoverButton = false;
        for(let i = 0; i < buttonRects.length; i++){
            let rect = buttonRects[i];
            if(mp.x >= rect.l && mp.x <= rect.r && mp.y >= rect.t && mp.y <= rect.b){
                hoverButton = true;
                break;
            }
        }
        if(hoverButton){
            gt.canvas.style.cursor = "pointer";
        }else{
            gt.canvas.style.cursor = "";
        }
    };
    let onMouseUp = function (view, mp, buttons, clicks, delta) {
        touchUpGrid(view, true, mp, false, mp, clicks);
        ivv(view);
    };

    //注册事件
    amde(canvas, gt, onMouseDown);
    amme(canvas, gt, onMouseMove);
    amwe(canvas, gt, onMouseWheel);
    amue(canvas, gt, onMouseUp, null);
    atbe(canvas, gt, onTouchBegin);
    atme(canvas, gt, onTouchMove);
    atee(canvas, gt, onTouchEnd, null);

    /*
    * 重置大小
    */
    let resizeAll = function () {
        canvas.width = document.documentElement.clientWidth;
        canvas.height = document.documentElement.clientHeight;
        scaleCanvas(gt);
        uvd(gt.views);
        iv(gt);
    };

    /*
    * 监听大小改变
    */
    window.onresize = function () {
        resizeAll();
    };

    /*
    * 旋转监听
    */
    window.onorientationchange = function () {
        resizeAll();
    };

    let imagesPath = new Map();
    let images = new Map();

    /*
    * 绘制单元格
    * grid:表格
    * row:行
    * column:列
    * c:单元格
    * paint:绘图对象
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    gt.onPaintGridCell = function (grid, row, column, c, paint, left, top, right, bottom) {
        let width = right - left, height = bottom - top;
        let colors = new Array();
        colors.push("rgb(170,178,189)");
        colors.push("rgb(150,123,220)");
        colors.push("rgb(140,192,81)");
        colors.push("rgb(219,68,83)");
        colors.push("rgb(216,112,173)"); 
        colors.push("rgb(246,187,67)");
        colors.push("rgb(59,174,218)");
        colors.push("rgb(75,137,220)");
        colors.push("rgb(185,63,150)");
        colors.push("rgb(233,87,62)");
        if (row.index < 2) {
            if (row.index == 1) {
                let eR = grid.rowHeight * 1.5;
                if (gt.isMobile) {
                    eR = 94;
                }
                if (grid.scrollV > 0) {
                    eR -= grid.scrollV / 3;
                }
                var text1s = new Array();
                var text2s = new Array();
                text1s.push("使用语言");
                text2s.push("20");
                text1s.push("支持平台");
                text2s.push("8");
                text1s.push("独立版本");
                text2s.push("70");
                text1s.push("创建项目");
                text2s.push("200+"); 
                if (!gt.isMobile && width > 500) {
                    text1s.push("研发年数");
                    text2s.push("4");
                    text1s.push("著作权");
                    text2s.push("7");
                    text1s.push("原创率");
                    text2s.push("99%");  
                    text1s.push("性能内存");
                    text2s.push("++");  
                    text1s.push("人工智能");
                    text2s.push("❖");  
                    text1s.push("多端互动");
                    text2s.push("✓");  
                }
                let tSub = 0;
                let tLeft = left + (right - left - text1s.length * (eR + tSub)) / 2;
                let avgTick = 720 / text1s.length;
                let nowIndex = parseInt((720 - tick) / avgTick);
                for (let i = 0; i < text1s.length; i++) {
                    let font1 = "Default,14";
                    let font2 = "Default,24";
                    if (grid.scrollV > 0) {
                        font2 = "Default," + (24 - grid.scrollV / 5).toString();
                        if (!gt.isMobile && width > 500) {
                            font2 = "Default," + (24 - grid.scrollV / 5).toString();
                        }
                        font1 = "Default," + (14 - grid.scrollV / 10).toString();
                    }
                    let tSize1 = paint.ts(text1s[i], font1);
                    let tSize2 = paint.ts(text2s[i], font2);
                    let firstRect = new FR(tLeft, top - eR / 2 - 10, tLeft + eR, top + eR / 2 - 10);
                    firstRect.l += 10;
                    firstRect.t += 10;
                    firstRect.r -= 10;
                    firstRect.b -= 10;
                    if (!paint.isMobile) {
                        firstRect.t += 8;
                        firstRect.b += 8;
                        firstRect.t += 5;
                        firstRect.b -= 5;
                    }else if(paint.isMobile){
                        firstRect.t += 12;
                        firstRect.b += 12;
                        firstRect.l -= 5;
                        firstRect.t -= 5;
                        firstRect.r += 5;
                        firstRect.b += 5;
                    }
                    let bColor = "rgb(42,138,195)";
                    let bColor2 = "rgba(42,138,195,200)";
                    let corner = 10;
                    if (!gt.isMobile && width > 500) {
                        corner = 0;
                    }
                    if (text1s.length > 4) {
                        bColor = colors[i % colors.length];
                        bColor2 = bColor;
                    }
                    if (tick > 0 && clickIndex <= 1 &&  nowIndex == i && paint.ds == "dark") {
                        if (grid.paint.ds == "dark") {
                            if (!gt.isMobile && width > 500) {
                                corner = 8;
                                paint.frr("rgba(21,24,28,150)", firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                                //paint.drr("rgb(50,50,50)", 1, 0, firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            }else{
                                corner = 8;
                                paint.frr("rgb(21,24,28)", firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            }
                            paint.dt(text1s[i], "rgb(150,150,150)", font1, firstRect.l + (firstRect.r - firstRect.l - tSize1.cx) / 2, firstRect.t + 20 - tSize1.cy / 2);
                            paint.dt(text2s[i], "rgb(200,200,200)", font2, firstRect.l + (firstRect.r - firstRect.l - tSize2.cx) / 2, firstRect.t + (firstRect.b - firstRect.t - tSize2.cy) / 2);
                        } else {
                            paint.frr("rgb(245,245,245)", firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            paint.drr("rgb(200,200,200)", 1, 0, firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            paint.dt(text1s[i], "rgb(100,100,100)", font1, firstRect.l + (firstRect.r - firstRect.l - tSize1.cx) / 2, firstRect.t + 20 - tSize1.cy / 2);
                            paint.dt(text2s[i], "rgb(50,50,50)", font2, firstRect.l + (firstRect.r - firstRect.l - tSize2.cx) / 2, firstRect.t + (firstRect.b - firstRect.t - tSize2.cy) / 2);
                        }
                    } else {
                        if (grid.paint.ds == "dark") {
                            if (!gt.isMobile && width > 500) {
                                corner = 8;
                                paint.frr("rgba(21,24,28,150)", firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                                //paint.drr("rgb(50,50,50)", 1, 0, firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            }else{
                                corner = 8;
                                paint.frr("rgb(21,24,28)", firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            }
                            paint.dt(text1s[i], "rgb(150,150,150)", font1, firstRect.l + (firstRect.r - firstRect.l - tSize1.cx) / 2, firstRect.t + 20 - tSize1.cy / 2);
                            paint.dt(text2s[i], "rgb(200,200,200)", font2, firstRect.l + (firstRect.r - firstRect.l - tSize2.cx) / 2, firstRect.t + (firstRect.b - firstRect.t - tSize2.cy) / 2);
                        } else {
                            paint.frr("rgb(245,245,245)", firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            paint.drr("rgb(200,200,200)", 1, 0, firstRect.l, firstRect.t, firstRect.r, firstRect.b, corner);
                            paint.dt(text1s[i], "rgb(100,100,100)", font1, firstRect.l + (firstRect.r - firstRect.l - tSize1.cx) / 2, firstRect.t + 20 - tSize1.cy / 2);
                            paint.dt(text2s[i], "rgb(50,50,50)", font2, firstRect.l + (firstRect.r - firstRect.l - tSize2.cx) / 2, firstRect.t + (firstRect.b - firstRect.t - tSize2.cy) / 2);
                        }
                    }
                    if (text1s.length > 4) {
                        paint.frr(colors[i % colors.length], firstRect.l + (firstRect.r - firstRect.l - 25 + grid.scrollV / 10) / 2, firstRect.b - 15 + grid.scrollV / 20, firstRect.l + (firstRect.r - firstRect.l + 25 - grid.scrollV / 10) / 2, firstRect.b - 10, 2);
                    } else {
                        paint.frr("rgb(42,138,195)", firstRect.l + (firstRect.r - firstRect.l - 25 + grid.scrollV / 10) / 2, firstRect.b - 15 + grid.scrollV / 20, firstRect.l + (firstRect.r - firstRect.l + 25 - grid.scrollV / 10) / 2, firstRect.b - 10, 2);
                    }
                    if (tick > 0 && clickIndex <= 1) {
                        let overTimes = tick;
                        if (overTimes > 360) {
                            overTimes -= 360;
                        }
                        let dRect = new FR(firstRect.l, firstRect.t, firstRect.r, firstRect.b);
                        let dWidth = Math.min(dRect.r - dRect.l, dRect.b - dRect.t) / 2;
                        let dInterval = 20;
                        paint.dr(bColor, 1, 0, dRect.l, dRect.t, dRect.r, dRect.b);
                        if (overTimes < 90) {
                            let fSize = (90 - overTimes) * (dWidth - dInterval) / 60;
                            let eSize = overTimes * (dWidth - dInterval) / 60;
                            paint.dl(bColor2, 3, 0, dRect.r - fSize, dRect.t, dRect.r, dRect.t);
                            paint.dl(bColor2, 3, 0, dRect.r, dRect.t, dRect.r, dRect.t + eSize);
                        }
                        else if (overTimes < 180) {
                            let fSize = (90 - (overTimes - 90)) * (dWidth - dInterval) / 60;
                            let eSize = (overTimes - 90) * (dWidth - dInterval) / 60;
                            paint.dl(bColor2, 3, 0, dRect.r, dRect.b - fSize, dRect.r, dRect.b);
                            paint.dl(bColor2, 3, 0, dRect.r, dRect.b, dRect.r - eSize, dRect.b);
                        }
                        else if (overTimes < 270) {
                            let fSize = (90 - (overTimes - 180)) * (dWidth - dInterval) / 60;
                            let eSize = (overTimes - 180) * (dWidth - dInterval) / 60;
                            paint.dl(bColor2, 3, 0, dRect.l, dRect.b, dRect.l + fSize, dRect.b);
                            paint.dl(bColor2, 3, 0, dRect.l, dRect.b, dRect.l, dRect.b - eSize);
                        }
                        else if (overTimes < 360) {
                            let fSize = (90 - (overTimes - 270)) * (dWidth - dInterval) / 60;
                            let eSize = (overTimes - 270) * (dWidth - dInterval) / 60;
                            paint.dl(bColor2, 3, 0, dRect.l, dRect.t, dRect.l + eSize, dRect.t);
                            paint.dl(bColor2, 3, 0, dRect.l, dRect.t, dRect.l, dRect.t + fSize);
                        }
                    }
                    tLeft += eR + tSub;
                }
                if(clickIndex > 1 && clickIndex != row.index){
                    if(paint.ds == "dark"){
                        paint.fr("rgba(0,0,0,200)", left, 0, right, bottom);
                    }else{
                        paint.fr("rgba(255,255,255,200)", left, 0, right, bottom);
                    }
                }
            }
        } else {
            if (!gt.isMobile && width > 500) {
                let dColor = "rgba(50,50,50)";
                let corner = 0;
                if (grid.paint.ds == "dark") {
                    if(gList.image2){
                        corner = 8;
                        paint.frr("rgba(21,24,28,230)", left + 14, top + 5, right - 14, bottom - 5, corner);
                    }else{
                        corner = 8;
                        paint.frr("rgba(21,24,28,150)", left + 14, top + 5, right - 14, bottom - 5, corner);
                    }
                } else {
                    dColor = "rgb(200,200,200)";
                    paint.frr("rgb(240,240,240)", left + 14, top + 5, right - 14, bottom - 5, corner);
                    paint.drr(dColor, 1, 0, left + 14, top + 5, right - 14, bottom - 5, corner)
                }
            } else {
                if (grid.paint.ds == "dark") {
                    paint.frr("rgb(21,24,28)", left + 14, top + 5, right - 14, bottom - 5, 10);
                } else {
                    paint.frr("rgb(240,240,240)", left + 14, top + 5, right - 14, bottom - 5, 10);
                }
            }
            let baseUpper = c.t1;
            if (c.t3 == "关于" && !gt.isMobile && width > 600) {
                baseUpper = "上海卷卷猫信息技术有限公司 版权所有@2023 " + baseUpper;
            }
            let font1 = "Default,15";
            let font2 = "Default,12";
            let font3 = "Default,14";
            let tSize = paint.ts(baseUpper, font1);
            if (c.t3 == "关于") {
                if (grid.paint.ds == "dark") {
                    paint.dt(baseUpper, "rgb(200,200,200)", font1, left + (width - tSize.cx) / 2, top + (height - tSize.cy) / 2); 
                } else {
                    paint.dt(baseUpper, "rgb(50,50,50)", font1, left + (width - tSize.cx) / 2, top + (height - tSize.cy) / 2); 
                }
                return;
            }
            let strVolume = c.t3;
            let strPrice = c.t4;
            let tSize2 = paint.ts(strVolume, font2);
            let drawColor = "rgb(255,0,0)";
            let t2Size = null;
            if(c.t2 && c.t2.length > 0){
                t2Size = paint.ts(c.t2, font2);
                let midY = top + height / 2 + tSize2.cy + 2;
                let t2Rect = new FR(left + 26 + 4, midY - t2Size.cy / 2, left + 26 + t2Size.cx + 4, midY + t2Size.cy / 2);
                let dX = t2Rect.l;
                let dY = t2Rect.t;
                t2Rect.l -= 4;
                t2Rect.r += 4;
                t2Rect.t -= 2;
                t2Rect.b += 3;
                paint.frr(colors[Number(c.lk) - 1], t2Rect.l, t2Rect.t, t2Rect.r, t2Rect.b, 4);
                paint.dt(c.t2, "rgb(255,255,255)", font2, dX, dY);
            }else{
                paint.fe(colors[Number(c.lk) - 1], left + 26, top + height / 2 + 3 + tSize2.cy - 4, left + 34, top + height / 2 + 3 + tSize2.cy + 4);
            }
            if (grid.paint.ds == "dark") {
                if(clickIndex == -1){
                    let nStr = c.n;
                    if(nStr && nStr.length > 0){
                        let nR = 11;
                        let nSize = paint.ts(nStr, font2);
                        let nX = left + 15;
                        let nY = top + 10;
                        paint.fe("rgb(50,50,50)", nX - nR, nY - nR, nX + nR, nY + nR);
                        paint.dt(nStr, "rgb(200,200,200)", font2, nX - nSize.cx / 2, nY - nSize.cy / 2 - 1);
                    }
                }
                paint.dt(baseUpper, "rgb(200,200,200)", font1, left + 26, top + height / 2 - tSize2.cy - tSize.cy / 2);
                if(c.t2 && c.t2.length > 0){
                    paint.dt(strVolume, "rgb(200,200,200)", font2, left + 39 + t2Size.cx, top + height / 2 + tSize2.cy + 3 - tSize2.cy / 2);
                }else{
                    paint.dt(strVolume, "rgb(200,200,200)", font2, left + 39, top + height / 2 + tSize2.cy + 3 - tSize2.cy / 2);
                }
            } else {
                if(clickIndex == -1){
                    let nStr = c.n;
                    if(nStr && nStr.length > 0){
                        let nR = 11;
                        let nSize = paint.ts(nStr, font2);
                        let nX = left + 15;
                        let nY = top + 10;
                        paint.fe("rgb(255,255,255)", nX - nR, nY - nR, nX + nR, nY + nR);
                        paint.de("rgb(200,200,200)", 1, 0, nX - nR, nY - nR, nX + nR, nY + nR);
                        paint.dt(nStr, "rgb(50,50,50)", font2, nX - nSize.cx / 2, nY - nSize.cy / 2 - 1);
                    }
                }
                paint.dt(baseUpper, "rgb(50,50,50)", font1, left + 26, top + height / 2 - tSize2.cy - tSize.cy / 2);
                if(c.t2 && c.t2.length > 0){
                    paint.dt(strVolume, "rgb(50,50,50)", font2, left + 39 + t2Size.cx, top + height / 2 + tSize2.cy + 3 - tSize2.cy / 2);
                }else{
                    paint.dt(strVolume, "rgb(50,50,50)", font2, left + 39, top + height / 2 + tSize2.cy + 3 - tSize2.cy / 2);
                }
            }
            let tSize5 = paint.ts("100000.00%", font3);
            let rate2 = 1 - 210 / width;
            if (gt.isMobile) {
                rate2 = 0.5;
            }
            let colRect = new FR(left + width * rate2 + 5, top + height / 2 - tSize5.cy - 4, left + width * rate2 + 5 + tSize5.cx, top + height / 2 + tSize5.cy + 3);
            if (!gt.isMobile && width > 500) {
                if (grid.paint.ds == "dark") {
                    paint.dtae(strPrice, "rgb(200,200,200)", font3, left + 200 + 30, top + height / 2 - tSize5.cy / 2, width - 260, left + 230 + 5 + tSize5.cy - tSize5.cy / 2);
                } else {
                    paint.dtae(strPrice, "rgb(50,50,50)", font3, left + 200 + 30, top + height / 2 - tSize5.cy / 2, width - 260, left + 230 + 5 + tSize5.cy - tSize5.cy / 2);
                }
                if (grid.paint.ds == "dark") {
                    paint.dl("rgb(0,0,0)", 2, 0, width - 240, top + 5, width - 240, bottom - 5);
                    paint.dl("rgb(0,0,0)", 2, 0, left + 210, top + 5, left + 210, bottom - 5);
                } else {
                    paint.dl("rgb(200,200,200)", 1, 0, width - 240, top + 5, width - 240, bottom - 5);
                    paint.dl("rgb(200,200,200)", 1, 0, left + 210, top + 5, left + 210, bottom - 5);
                }
                //paint.dl("rgb(50,50,50)", 1, 0, left + 200 + 5 - 10, top, left + 200 + 5 - 10, bottom);
                //paint.dl("rgb(50,50,50)", 1, 0, width - 220, top, width - 220, bottom);
            }
            if (grid.paint.ds == "dark") {
                if(gList.image2){
                    paint.frr("rgba(32,36,38,230)", colRect.l, top + 15, colRect.r, bottom - 15, 5);
                }else{
                    if (!gt.isMobile && width > 500) {
                        paint.frr("rgba(32,36,38,100)", colRect.l, top + 15, colRect.r, bottom - 15, 5);
                    }else{
                        paint.frr("rgb(32,36,38)", colRect.l, top + 15, colRect.r, bottom - 15, 5);
                    }
                }
                //paint.drr("rgb(75,75,75)", 1, 0, colRect.l, colRect.t, colRect.r, colRect.b, 10);
            } else {
                paint.frr("rgb(255,255,255)", colRect.l, top + 15, colRect.r, bottom - 15, 5);
                paint.drr("rgb(200,200,200)", 1, 0, colRect.l, top + 15, colRect.r, bottom - 15, 5);
            }
            if(mouseMovePoint.x >= colRect.l && mouseMovePoint.x <= colRect.r && mouseMovePoint.y >= top + 15 && mouseMovePoint.y <= bottom - 15){
                paint.drr("rgb(42,138,195)", 1, 0, colRect.l, top + 15, colRect.r, bottom - 15, 5);
            }
            buttonRects.push(new FR(colRect.l, top + 15, colRect.r, bottom - 15, 5));
            let diffX = colRect.r - colRect.l + 10;
            if (c.lt2.length > 0) {
                if(c.lt2 == "纪录片"){
                    let zRect = new FR(colRect.l + diffX + 10, top + 15 + 10, colRect.r + diffX - 10, bottom - 15 - 10);
                    if (grid.paint.ds == "dark") {
                        if (!gt.isMobile && width > 500) {
                            paint.frr("rgba(32,36,38,100)", zRect.l, zRect.t, zRect.r, zRect.b, 5);
                        }else{
                            paint.frr("rgb(32,36,38)", zRect.l, zRect.t, zRect.r, zRect.b, 5);
                        }
                        paint.drr("rgb(100,100,100)", 1, 0, zRect.l, zRect.t, zRect.r, zRect.b, 5);
                    }else{
                        paint.frr("rgb(255,255,255)", zRect.l, zRect.t, zRect.r, zRect.b, 5);
                        paint.drr("rgb(150,150,150)", 1, 0, zRect.l, zRect.t, zRect.r, zRect.b, 5);
                    }
                    if(mouseMovePoint.x >= zRect.l && mouseMovePoint.x <= zRect.r && mouseMovePoint.y >= zRect.t && mouseMovePoint.y <= zRect.b){
                        paint.drr("rgb(42,138,195)", 1, 0, zRect.l, zRect.t, zRect.r, zRect.b, 5);
                    }
                    buttonRects.push(new FR(zRect.l, zRect.t, zRect.r, zRect.b));
                }else{
                    if (grid.paint.ds == "dark") {
                        if(gList.image2){
                            paint.frr("rgba(32,36,38,230)", colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15, 5);
                        }else{
                            if (!gt.isMobile && width > 500) {
                                paint.frr("rgba(32,36,38,100)", colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15, 5);
                            }else{
                                paint.frr("rgb(32,36,38)", colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15, 5);
                            }
                        }
                        //paint.drr("rgb(75,75,75)", 1, 0, colRect.l + diffX, colRect.t, colRect.r + diffX, colRect.b, 4);
                    } else {
                        paint.frr("rgb(255,255,255)", colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15, 5);
                        paint.drr("rgb(200,200,200)", 1, 0, colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15, 5);
                    }
                    if(mouseMovePoint.x >= colRect.l + diffX && mouseMovePoint.x <= colRect.r + diffX && mouseMovePoint.y >= top + 15 && mouseMovePoint.y <= bottom - 15){
                        paint.drr("rgb(42,138,195)", 1, 0, colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15, 5);
                    }
                    buttonRects.push(new FR(colRect.l + diffX, top + 15, colRect.r + diffX, bottom - 15));
                }
            }
            c.diffX = diffX;
            let tSize4 = paint.ts(c.lt1, font3);
            let tSize6 = paint.ts(c.lt2, font3);
            let offsetRight = 15;
            if (c.i) {
                if (!c.initImage) {
                    c.initImage = true;
                    let i = new Image();
                    i.onload = function () {
                        c.image2 = i;
                        ivv(grid);
                    };
                    i.src = c.i;
                }
            }
            if (grid.paint.ds == "dark") {
                paint.dt(c.lt1, "rgb(200,200,200)", font3, left + width * rate2 + 5 + tSize5.cx / 2 - tSize4.cx / 2 - 15, top + height / 2 - tSize4.cy / 2);
            } else {
                paint.dt(c.lt1, "rgb(50,50,50)", font3, left + width * rate2 + 5 + tSize5.cx / 2 - tSize4.cx / 2 - 15, top + height / 2 - tSize4.cy / 2);
            }
            let tLeft1 = left + width * rate2 + 5 + tSize5.cx / 2 - tSize4.cx / 2 - 15 + tSize4.cx + 10;
            let tLeftRect = new FR(tLeft1 + 2, top + height / 2 - 10, tLeft1 + 20 - 2, top + height / 2 + 10);
            if(c.lt1 == "运行" || c.lt1 == "视频" || c.lt1 == "下载" || c.lt1 == "打开"){
                let points1 = new Array();
                let pR = 6;
                points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 - pR, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2 - pR));
                points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 - pR, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2 + pR));
                points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 + pR, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2));
                paint.fpg("rgb(170,178,189)", points1);
            }else{
                paint.drr("rgb(150,150,150)", 1, 0, tLeftRect.l, tLeftRect.t, tLeftRect.r, tLeftRect.b, 2);
                paint.dl("rgb(150,150,150)", 1, 0, tLeftRect.l + 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 4, tLeftRect.r - 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 4);
                paint.dl("rgb(150,150,150)", 1, 0, tLeftRect.l + 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2, tLeftRect.l + 7, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2);
                paint.dl("rgb(150,150,150)", 1, 0, tLeftRect.l + 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) * 3 / 4, tLeftRect.l + 7, tLeftRect.t + (tLeftRect.b - tLeftRect.t) * 3 / 4);
                paint.dt("A", "rgb(150,150,150)", "Default,10.5", tLeftRect.l + 8, tLeftRect.t + 8);
            }
            if (c.lt2.length > 0) {
                if (c.image2) {
                    let tLeft = left + width * rate2 + 5 + tSize5.cx / 2 - tSize6.cx / 2 + diffX - offsetRight;
                    if (grid.paint.ds == "dark") {
                        paint.dt(c.lt2, "rgb(200,200,200)", font3, tLeft, top + height / 2 - tSize4.cy / 2);
                    } else {
                        paint.dt(c.lt2, "rgb(50,50,50)", font3, tLeft, top + height / 2 - tSize4.cy / 2);
                    }
                    paint.drawImage(c.image2, tLeft + tSize6.cx + 10, top + height / 2 - 12, tLeft + tSize6.cx + 34, top + height / 2 + 12);
                } else {
                    if(c.lt2 == "纪录片"){
                        let tLeft = left + width * rate2 + tSize5.cx / 2  + diffX - offsetRight;
                        if (grid.paint.ds == "dark") {
                            paint.dt(c.lt2, "rgb(200,200,200)", font3, tLeft, top + height / 2 - tSize4.cy / 2);
                        } else {
                            paint.dt(c.lt2, "rgb(50,50,50)", font3, tLeft, top + height / 2 - tSize4.cy / 2);
                        }
                    }else{
                        let tLeft = left + width * rate2 + 5 + tSize5.cx / 2 - tSize6.cx / 2 + diffX - offsetRight;
                        if (grid.paint.ds == "dark") {
                            paint.dt(c.lt2, "rgb(200,200,200)", font3, tLeft, top + height / 2 - tSize4.cy / 2);
                        } else {
                            paint.dt(c.lt2, "rgb(50,50,50)", font3, tLeft, top + height / 2 - tSize4.cy / 2);
                        }
                        let tLeft1 = tLeft + tSize6.cx + 10;
                        tLeftRect = new FR(tLeft1 + 2, top + height / 2 - 10, tLeft1 + 20 - 2, top + height / 2 + 10);
                        if(c.lt2 == "图片"){
                            tLeftRect.t += 2;
                            tLeftRect.b -= 2;
                            paint.drr("rgb(150,150,150)", 1, 0, tLeftRect.l, tLeftRect.t, tLeftRect.r, tLeftRect.b, 2);
                            let points1 = new Array();
                            points1.push(new FP(tLeftRect.l + 1, tLeftRect.b));
                            points1.push(new FP(tLeftRect.l + 5, tLeftRect.b - 12));
                            points1.push(new FP(tLeftRect.l + 12, tLeftRect.b));
                            paint.fpg("rgb(150,150,150)", points1);
                            let points2 = new Array();
                            points2.push(new FP(tLeftRect.l + 7, tLeftRect.b));
                            points2.push(new FP(tLeftRect.l + 11, tLeftRect.b - 10));
                            points2.push(new FP(tLeftRect.l + 15, tLeftRect.b));
                            paint.fpg("rgb(150,150,150)", points2);
                            let lR = 2;
                            paint.fe("rgb(150,150,150)", tLeftRect.l + (tLeftRect.r - tLeftRect.l) * 3 / 4 - lR, 
                            tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 4 - lR, tLeftRect.l + (tLeftRect.r - tLeftRect.l) * 3 / 4 + lR, 
                            tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 4 + lR);
                        }else if(c.lt2 == "示例"){
                            let points1 = new Array();
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 - 3, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2 - 8));
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 + 3, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2 - 8));
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 + 3, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2));
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 + 8, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2));
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2 + 9));
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 - 8, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2));
                            points1.push(new FP(tLeftRect.l + (tLeftRect.r - tLeftRect.l) / 2 - 3, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2));
                            paint.fpg("rgb(170,178,189)", points1);
                        }else{
                            paint.drr("rgb(175,175,175)", 1, 0, tLeftRect.l, tLeftRect.t, tLeftRect.r, tLeftRect.b, 2);
                            paint.dl("rgb(175,175,175)", 1, 0, tLeftRect.l + 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 4, tLeftRect.r - 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 4);
                            paint.dl("rgb(175,175,175)", 1, 0, tLeftRect.l + 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2, tLeftRect.l + 7, tLeftRect.t + (tLeftRect.b - tLeftRect.t) / 2);
                            paint.dl("rgb(175,175,175)", 1, 0, tLeftRect.l + 4, tLeftRect.t + (tLeftRect.b - tLeftRect.t) * 3 / 4, tLeftRect.l + 7, tLeftRect.t + (tLeftRect.b - tLeftRect.t) * 3 / 4);
                            paint.dt("A", "rgb(175,175,175)", "Default,10.5", tLeftRect.l + 8, tLeftRect.t + 8);
                        }
                    }
                }
            }
            if (tick > 0 && clickIndex == row.index) {
                let overTimes = tick;
                if (overTimes > 360) {
                    overTimes -= 360;
                }
                let dRect = new FR(left + 14, top + 5, right - 14, bottom - 5);
                let dWidth = Math.min(dRect.r - dRect.l, dRect.b - dRect.t);
                let dInterval = 20;
                let dcWidth = grid.size.cx * 1.5;
                let dcWidth2 = 400;
                if (paint.isMobile) {
                    dcWidth = grid.size.cx;
                    dcWidth2 = 200;
                }
                let showRect = new FR(-dcWidth2 + dcWidth * (360 - overTimes) / dcWidth2, dRect.t, dcWidth * (360 - overTimes) / dcWidth2, dRect.b);
                if (showRect.l < dRect.l) {
                    showRect.l = dRect.l;
                }
                if (showRect.l > dRect.r) {
                    showRect.l = dRect.r;
                }
                if (showRect.r < dRect.l) {
                    showRect.r = dRect.l;
                }
                if (showRect.r > dRect.r) {
                    showRect.r = dRect.r;
                }
                if(replayTick > 9){
                    paint.fr("rgba(42,138,195,100)", showRect.l, showRect.t, showRect.r, showRect.b);
                }
                paint.dr("rgb(42,138,195)", 1, 0, dRect.l, dRect.t, dRect.r, dRect.b);
                if(replayTick > 9){
                    if (overTimes < 90) {
                        let fSize = (90 - overTimes) * (dWidth - dInterval) / 60;
                        let eSize = overTimes * (dWidth - dInterval) / 60;
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.r - fSize, dRect.t, dRect.r, dRect.t);
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.r, dRect.t, dRect.r, dRect.t + eSize);
                    }
                    else if (overTimes < 180) {
                        let fSize = (90 - (overTimes - 90)) * (dWidth - dInterval) / 60;
                        let eSize = (overTimes - 90) * (dWidth - dInterval) / 60;
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.r, dRect.b - fSize, dRect.r, dRect.b);
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.r, dRect.b, dRect.r - eSize, dRect.b);
                    }
                    else if (overTimes < 270) {
                        let fSize = (90 - (overTimes - 180)) * (dWidth - dInterval) / 60;
                        let eSize = (overTimes - 180) * (dWidth - dInterval) / 60;
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.l, dRect.b, dRect.l + fSize, dRect.b);
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.l, dRect.b, dRect.l, dRect.b - eSize);
                    }
                    else if (overTimes < 360) {
                        let fSize = (90 - (overTimes - 270)) * (dWidth - dInterval) / 60;
                        let eSize = (overTimes - 270) * (dWidth - dInterval) / 60;
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.l, dRect.t, dRect.l + eSize, dRect.t);
                        paint.dl("rgba(42,138,195,200)", 3, 0, dRect.l, dRect.t, dRect.l, dRect.t + fSize);
                    }
                }
                let t1 = 6, t2 = 24;
                paint.beginPath();
                paint.al(dRect.l + t1, dRect.t + t2, dRect.l + t1, dRect.t + t1);
                paint.al(dRect.l + t1, dRect.t + t1, dRect.l + t2, dRect.t + t1);
                paint.dp("rgba(42,138,195,200)", 2, 0);
                paint.closePath();
                paint.beginPath();
                paint.al(dRect.l + t1, dRect.b - t2, dRect.l + t1, dRect.b - t1);
                paint.al(dRect.l + t1, dRect.b - t1, dRect.l + t2, dRect.b - t1);
                paint.dp("rgba(42,138,195,200)", 2, 0);
                paint.closePath();
                paint.beginPath();
                paint.al(dRect.r - t1, dRect.t + t2, dRect.r - t1, dRect.t + t1);
                paint.al(dRect.r - t1, dRect.t + t1, dRect.r - t2, dRect.t + t1);
                paint.dp("rgba(42,138,195,200)", 2, 0);
                paint.closePath();
                paint.beginPath();
                paint.al(dRect.r - t1, dRect.b - t2, dRect.r - t1, dRect.b - t1);
                paint.al(dRect.r - t1, dRect.b - t1, dRect.r - t2, dRect.b - t1);
                paint.dp("rgba(42,138,195,200)", 2, 0);
                paint.closePath();
            }
            if(clickIndex > 1 && clickIndex != row.index){
                if(paint.ds == "dark"){
                    paint.fr("rgba(0,0,0,200)", left, top, right, bottom);
                }else{
                    paint.fr("rgba(255,255,255,200)", left, top, right, bottom);
                }
            }
        }
    };

    /*
    * 绘制列
    * grid:表格
    * column:列
    * paint:绘图对象
    * left:左侧坐标
    * top:上方坐标
    * right:右侧坐标
    * bottom:下方坐标
    */
    gt.onPaintGridColumn = function (grid, column, paint, left, top, right, bottom) {
        if (grid.scrollV < 150) {
            let width = right - left, height = bottom - top;
            let font2 = "Default,16";
            let font3 = "Default,13";
            let str = "@花卷猫";
            let str2 = "(国产化基建 非互联网/金融科技公司)";
            let tSize = paint.ts("AAA", font2);
            let tSize2 = paint.ts("AAA", font3);
            let tSize3 = paint.ts(str, font2);
            if (!column.image2) {
                let i = new Image();
                i.onload = function () {
                    column.image2 = i;
                    ivv(grid);
                };
                i.onerror = function () {
                    column.image2 = i;
                    ivv(grid);
                };
                i.src = "images/logo.png";
            }
            else {
                let iR = 20;
                let imageRect = new FR(20, 30 - iR, 20 + iR * 2, 30 + iR);
                if (paint.ds == "light") {
                    paint.fe("rgb(240,240,240)", imageRect.l, imageRect.t, imageRect.r, imageRect.b);
                } else {
                    paint.fe("rgb(32,36,38)", imageRect.l, imageRect.t, imageRect.r, imageRect.b);
                }

                if (paint.ds == "light") {
                    paint.dt(str, "rgb(0,0,0)", font2, imageRect.r + 10, imageRect.t + (imageRect.b - imageRect.t) / 2 - tSize.cy / 2);
                    paint.dt(str2, "rgb(100,100,100)", font3, imageRect.r + 15 + tSize3.cx, imageRect.t + (imageRect.b - imageRect.t) / 2 - tSize2.cy / 2);
                } else {
                    paint.dt(str, "rgb(200,200,200)", font2, imageRect.r + 10, imageRect.t + (imageRect.b - imageRect.t) / 2 - tSize.cy / 2);
                    paint.dt(str2, "rgb(150,150,150)", font3, imageRect.r + 15 + tSize3.cx, imageRect.t + (imageRect.b - imageRect.t) / 2 - tSize2.cy / 2);
                }
                imageRect.l += 6;
                imageRect.t += 6;
                imageRect.r -= 6;
                imageRect.b -= 6;
                paint.drawImage(column.image2, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            }
            let bR = 10;
            let blackWhiteRect = new FR(grid.size.cx - 25 - bR, 25 - bR, grid.size.cx - 25 + bR, 25 + bR);
            if (paint.ds == "light") {
                paint.fe("rgb(175,175,175)", blackWhiteRect.l, blackWhiteRect.t, blackWhiteRect.r, blackWhiteRect.b);
            } else {
                paint.fe("rgb(70,76,79)", blackWhiteRect.l, blackWhiteRect.t, blackWhiteRect.r, blackWhiteRect.b);
            }
            blackWhiteRect.l += bR;
            blackWhiteRect.r += bR;
            paint.fe(grid.backColor, blackWhiteRect.l, blackWhiteRect.t, blackWhiteRect.r, blackWhiteRect.b);
        }
    };

    /*
    * 重绘边线的实现方法
    * view:视图
    * paint:绘图对象
    * clipRect:裁剪区域
    */
    gt.onPaint = function (view, paint, clipRect) {
        let width = view.size.cx;
        paint.fr(view.backColor, 0, 0, view.size.cx, view.size.cy);
        buttonRects = [];
        drawGrid(view, paint, clipRect);
    };

    /*
    * 重绘边线的实现方法
    * view:视图
    * paint:绘图对象
    * clipRect:裁剪区域
    */
    gt.onPaintBorder = function (view, paint, clipRect) {
        drawGridScrollBar(view, paint, clipRect);
        if (clickIndex > 1) {
            let row = gList.rows[clickIndex];
            let c = row.cells[0];
            let dFont = "Default,14";
            let gSize = paint.ts(c.t4, dFont);
            let divTop = 0;
            let bounds = new FR(0, clickIndex * gList.rowHeight + gList.headerHeight - gList.scrollV, gList.size.cx, (clickIndex + 1) * gList.rowHeight + gList.headerHeight - gList.scrollV);
            let dR = 300;
            let mobileMode = false;
            if (paint.isMobile || gList.size.cx <= 500){
                dR = 250;
                mobileMode = true;
            }
            bounds = new FR(0, (clickIndex - 2) * gList.rowHeight + gList.headerHeight - gList.scrollV + 100, gList.size.cx, (clickIndex - 2 + 1) * gList.rowHeight + gList.headerHeight - gList.scrollV + 100);
            let cellTop = bounds.t;
            let cellBottom = bounds.b;
            let gHeight = 0;
            if (mobileMode || gSize.cx > gList.size.cx - 40) {
                gHeight = gList.rowHeight;   
                bounds.l += 10;
                bounds.r -= 10;
                let lineCount = 0;
                let dt = "";
                let pos = 0;
                let textLength = c.t4.length;
                while (pos < textLength) {
                    dt += c.t4[pos];
                    let dSize = paint.ts(dt, dFont);
                    if (dSize.cx > bounds.r - 40 || pos == textLength - 1) {
                        lineCount++;
                        dt = "";
                    }
                    pos++;
                }
                if(c.p){
                    lineCount++;
                }
                if(c.d && mobileMode){
                    lineCount++;
                }
                if (bounds.t < gList.size.cy / 2) {
                    bounds.t += gList.rowHeight;
                    bounds.b += gList.rowHeight;
                    if (bounds.b - bounds.t - 60 < gSize.cy * lineCount) {
                        bounds.b = bounds.t + 60 + gSize.cy * lineCount;
                    }
                    bounds.b = bounds.t + lineCount * (gSize.cy + 7) + 15;
                    divTop = bounds.b + 10;
                } else {
                    bounds.t -= gList.rowHeight;
                    bounds.b -= gList.rowHeight;
                    if (bounds.b - bounds.t - 60 < gSize.cy * lineCount) {
                        bounds.t = cellTop - lineCount * (gSize.cy + 7) - 15;
                    }
                    bounds.b = bounds.t + lineCount * (gSize.cy + 7) + 15;
                    divTop = bounds.t - dR - 10;
                }
                let textColor = "rgb(200,200,200)";
                if (paint.ds == "light") {
                    paint.frr("rgba(240,240,240,200)", bounds.l, bounds.t, bounds.r, bounds.b, 0);
                    paint.drr("rgb(175,175,175)", 1, 0, bounds.l, bounds.t, bounds.r, bounds.b, 0);
                    textColor = "rgb(50,50,50)";
                } else {
                    paint.frr("rgba(15,15,15,200)", bounds.l, bounds.t, bounds.r, bounds.b, 0);
                    paint.drr("rgb(50,50,50)", 1, 0, bounds.l, bounds.t, bounds.r, bounds.b, 0);
                    textColor = "rgb(200,200,200)";
                }
                dt = "";
                let dTop = bounds.t + 10;
                pos = 0;
                textLength = c.t4.length;
                while (pos < textLength) {
                    dt += c.t4[pos];
                    let dSize = paint.ts(dt, dFont);
                    if (dSize.cx > bounds.r - 40 || pos == textLength - 1) {
                        paint.dt(dt, textColor, dFont, bounds.l + 10, dTop);
                        dt = "";
                        dTop += gSize.cy + 7;
                    }
                    pos++;
                }
                if(c.p){
                    let pText = "支持平台    " + c.p;
                    if(row.index < 10){
                        pText = "同类产品    " + c.p;
                    }
                    let pSize = paint.ts(pText, dFont);
                    if(paint.ds == "dark"){
                        paint.dl("rgb(50,50,50)", 1, 0, bounds.l + 75, dTop, bounds.l + 75, bounds.b);
                        paint.dl("rgb(50,50,50)", 1, 0, bounds.l, dTop, bounds.r, dTop);
                    }else{
                        paint.dl("rgb(175,175,175)", 1, 0, bounds.l + 75, dTop, bounds.l + 75, bounds.b);
                        paint.dl("rgb(175,175,175)", 1, 0, bounds.l, dTop, bounds.r, dTop);
                    }
                    paint.dt(pText, textColor, dFont, bounds.l + 10, dTop + 7);
                    if(c.d){
                        let pText2 = "同类框架    " + c.d;
                        let pSize2 = paint.ts(pText2, dFont);
                        if(mobileMode){
                            if(paint.ds == "dark"){
                                paint.dl("rgb(50,50,50)", 1, 0, bounds.l, dTop + (gSize.cy + 10), bounds.r, dTop + (gSize.cy + 10));
                            }else{
                                paint.dl("rgb(175,175,175)", 1, 0, bounds.l, dTop + (gSize.cy + 10), bounds.r, dTop + (gSize.cy + 10));
                            }
                            paint.dt(pText2, textColor, dFont, bounds.l + 10, dTop + 7 + (gSize.cy + 7) + 2);
                        }else{
                            if(paint.ds == "dark"){
                                paint.dl("rgb(50,50,50)", 1, 0, bounds.l + pSize.cx + 30, dTop, bounds.l + pSize.cx + 30, bounds.b);
                                paint.dl("rgb(50,50,50)", 1, 0, bounds.l + pSize.cx + 105, dTop, bounds.l + pSize.cx + 105, bounds.b);
                            }else{
                                paint.dl("rgb(175,175,175)", 1, 0, bounds.l + pSize.cx + 30, dTop, bounds.l + pSize.cx + 30, bounds.b);
                                paint.dl("rgb(175,175,175)", 1, 0, bounds.l + pSize.cx + 105, dTop, bounds.l + pSize.cx + 105, bounds.b);
                            }
                            paint.dt(pText2, textColor, dFont, bounds.l + pSize.cx + 40, dTop + 7);
                        }
                    }
                }
            }
            if(bounds.t < cellTop){
                if(bounds.t < gList.size.cy - bounds.b - gList.rowHeight){
                    divTop = cellBottom + 10;
                }else{
                    divTop = bounds.t - dR - 10;
                }
            }else{
                if(bounds.t < gList.size.cy - bounds.b + gList.rowHeight){
                    divTop = bounds.b + 10;
                }else{
                    divTop = bounds.t - dR - 10 - gHeight;
                }
            }
            if(c.r){
                if(replayTick <= 1 && tick <= 360){
                    return;
                }
                let colors = new Array();
                colors.push("rgb(170,178,189)");
                colors.push("rgb(150,123,220)");
                colors.push("rgb(140,192,81)");
                colors.push("rgb(219,68,83)");
                colors.push("rgb(216,112,173)"); 
                colors.push("rgb(246,187,67)");
                colors.push("rgb(59,174,218)");
                colors.push("rgb(75,137,220)");
                colors.push("rgb(185,63,150)");
                colors.push("rgb(233,87,62)");
                let divRect = new FR(gList.size.cx / 2 - dR / 2, divTop, gList.size.cx / 2 + dR / 2, divTop + dR);
                let alpha = "230";
                if(replayTick == 10 && tick > 360){
                    alpha = 230 - 230 * (tick - 360) / 360;
                }
                let strColor = colors[Number(c.lk) - 1].replace("rgb(", "").replace(")", "");
                if(paint.ds == "dark"){
                    paint.fe("rgba(15,15,15," + alpha.toString() + ")", divRect.l, divRect.t, divRect.r, divRect.b);
                    paint.de("rgb(50,50,50)", 1, 0, divRect.l, divRect.t, divRect.r, divRect.b);
                }else{
                    paint.fe("rgba(240,240,240," + alpha.toString() + ")", divRect.l, divRect.t, divRect.r, divRect.b);
                    paint.de("rgb(150,150,150)", 1, 0, divRect.l, divRect.t, divRect.r, divRect.b);
                }
                let aR = 50;
                if(paint.ds == "dark"){
                    paint.fe("rgba(0,0,0,200)", divRect.l + aR, divRect.t + aR, divRect.r - aR, divRect.b - aR);
                    paint.de("rgb(50,50,50)", 1, 0, divRect.l + aR, divRect.t + aR, divRect.r - aR, divRect.b - aR);
                }else{
                    paint.fe("rgba(255,255,255,200)", divRect.l + aR, divRect.t + aR, divRect.r - aR, divRect.b - aR);
                    paint.de("rgb(150,150,150)", 1, 0, divRect.l + aR, divRect.t + aR, divRect.r - aR, divRect.b - aR);
                }
                let strs = c.r.split(",");
                let oX = divRect.l + (divRect.r - divRect.l) / 2;
                let oY = divRect.t + (divRect.b - divRect.t) / 2;
                let r = (divRect.r - divRect.l) / 2 - 50;
                let rPoints = new Array();
                let rPoints2 = new Array();
                let rPoints3 = new Array();
                let rPoints4 = new Array();
                let titles = new Array();
                titles.push("性能");
                titles.push("内存");
                titles.push("体积");
                titles.push("上手");
                titles.push("功能");
                titles.push("兼容");
                let tFont = "Default,14";
                if(c.lk == "2"){
                    titles = new Array();
                    titles.push("可视设计");
                    titles.push("浏览器");
                    titles.push("多端互动");
                    titles.push("网站收集");
                    titles.push("工具箱");
                    titles.push("代码编辑");
                }else if(c.lk == "1"){
                    titles = new Array();
                    if(row.index > 3){
                        titles.push("研发");
                        titles.push("设计");
                        titles.push("运营");
                        titles.push("自媒体");
                        titles.push("销售");
                        titles.push("项目");
                    }else{
                        titles.push("图形");
                        titles.push("存储");
                        titles.push("通讯服务");
                        titles.push("算法");
                        titles.push("自动化");
                        titles.push("人工智能");
                    }
                }else if(c.lk == "6"){
                    titles = new Array();
                    titles.push("基础软件");
                    titles.push("自动化");
                    titles.push("工业软件");
                    titles.push("生产力");
                    titles.push("互联网");
                    titles.push("金融量化");
                }
                let totalRate = 0;
                for(let i = 0; i < strs.length; i++){
                    totalRate = totalRate + parseInt(strs[i]);
                }
                for(let i = 0; i < strs.length; i++){
                    let angle = i * 60 - 60;
                    let angle2 = angle;
                    let cR = r * parseInt(strs[i]) / 100;
                    if(replayTick == 10 && tick > 360){
                        let dTick = (720 - tick);
                        cR = dTick * cR / 360;
                        angle2 += dTick;
                    }else if(replayTick == 1){
                        let dTick = 360 - (720 - tick);
                        cR = dTick * cR / 360;
                        angle2 -= dTick;
                    }
                    let cX = oX + (cR * Math.cos(angle2 * 3.14 / 180));
                    let cY = oY + (cR * Math.sin(angle2 * 3.14 / 180));
                    let cX2 = oX + (r * Math.cos(angle * 3.14 / 180));
                    let cY2 = oY + (r * Math.sin(angle * 3.14 / 180));
                    let cX3 = oX + (r / 3 * Math.cos(angle * 3.14 / 180));
                    let cY3 = oY + (r / 3 * Math.sin(angle * 3.14 / 180));
                    let cX4 = oX + (r * 2 / 3 * Math.cos(angle * 3.14 / 180));
                    let cY4 = oY + (r * 2 / 3 * Math.sin(angle * 3.14 / 180));
                    rPoints.push(new FP(cX, cY));
                    rPoints2.push(new FP(cX2, cY2));
                    rPoints3.push(new FP(cX3, cY3));
                    rPoints4.push(new FP(cX4, cY4));
                    let cX5 = oX + ((r + 25) * Math.cos(angle * 3.14 / 180));
                    let cY5 = oY + ((r + 25) * Math.sin(angle * 3.14 / 180));
                    let rtSize = paint.ts(titles[i], tFont);
                    if(paint.ds == "dark"){
                        paint.dt(titles[i], "rgb(200,200,200)", tFont, cX5 - rtSize.cx / 2, cY5 - rtSize.cy / 2);
                    }else{
                        paint.dt(titles[i], "rgb(50,50,50)", tFont, cX5 - rtSize.cx / 2, cY5 - rtSize.cy / 2);
                    }
                    let tPos = 30;
                    let cX6 = oX + (dR / 2 * Math.cos((angle + tPos) * 3.14 / 180));
                    let cY6 = oY + (dR / 2 * Math.sin((angle + tPos) * 3.14 / 180));
                    let dPos = 20;
                    if(replayTick == 10 && tick > 360){
                        let dTick = (720 - tick);
                        dPos = dTick * dPos / 360;
                    }
                    
                    let cX7 = oX + ((dR / 2 - dPos) * Math.cos((angle + tPos) * 3.14 / 180));
                    let cY7 = oY + ((dR / 2 - dPos) * Math.sin((angle + tPos) * 3.14 / 180));
                    if(paint.ds == "dark"){
                        paint.dl("rgb(50,50,50)", 2, 0, cX6, cY6, cX7, cY7);
                    }else{
                        paint.dl("rgb(150,150,150)", 1, 0, cX6, cY6, cX7, cY7);
                    }
                }
                let dColor = "rgb(30,30,30)";
                if(paint.ds == "light"){
                    dColor = "rgb(220,220,220)";
                }
                paint.dl(dColor, 1, 0, rPoints2[0].x, rPoints2[0].y, rPoints2[3].x, rPoints2[3].y);
                paint.dl(dColor, 1, 0, rPoints2[1].x, rPoints2[1].y, rPoints2[4].x, rPoints2[4].y);
                paint.dl(dColor, 1, 0, rPoints2[2].x, rPoints2[2].y, rPoints2[5].x, rPoints2[5].y);
                paint.dpg(dColor, 1, 0, rPoints3);
                paint.dpg(dColor, 1, 0, rPoints4);
                paint.fpg("rgba(" + strColor + ",80)", rPoints);
                paint.dpg("rgb(" + strColor + ")", 1, 0, rPoints);
                if(c.s && replayTick > 3 && replayTick < 10){
                    let pIndex = 9 - replayTick;
                    for(let i = 0; i < strs.length; i++){
                        let angle = i * 60 - 60;
                        let angle2 = angle;
                        if(pIndex == i || pIndex == -1){
                            let cR = r * parseInt(strs[i]) / 100;
                            let cX = oX + (cR * Math.cos(angle2 * 3.14 / 180));
                            let cY = oY + (cR * Math.sin(angle2 * 3.14 / 180));
                            let pR = 4;
                            let pR2 = 7;
                            if(tick > 360){
                                let dTick = (720 - tick);
                                pR = pR / 2 + dTick * pR / 2 / 360;
                                pR2 = pR2 / 2 + dTick * pR2 / 2 / 360;
                            }
                            paint.fe("rgb(" + strColor + ")", cX - pR, cY - pR, cX + pR, cY + pR);
                            paint.de("rgb(" + strColor + ")", 1.5, 0, cX - pR2, cY - pR2, cX + pR2, cY + pR2);

                            let pStr = strs[i];
                            let star = parseInt(strs[i]);
                            if(star >= 95){
                                pStr = "A+";
                            }else if(star >= 90){
                                pStr = "A";
                            }else if(star >= 85){
                                pStr = "B+";
                            }else if(star >= 80){
                                pStr = "B";
                            }else if(star >= 75){
                                pStr = "C+";
                            }else if(star >= 70){
                                pStr = "C";
                            }else if(star >= 65){
                                pStr = "D+";
                            }else if(star >= 60){
                                pStr = "D";
                            }else{
                                pStr = "E";
                            }
                            let pFontSize = 18;
                            let pFont = "Default," + pFontSize.toString();
                            let pSize = paint.ts(pStr, pFont);

                            let cX2 = oX + ((cR - 22)* Math.cos(angle2 * 3.14 / 180));
                            let cY2 = oY + ((cR - 22) * Math.sin(angle2 * 3.14 / 180));
                            paint.dt(pStr, "rgb(" + strColor + ")", pFont, cX2 - pSize.cx / 2, cY2 - pSize.cy / 2);
                        }
                    }
                }
                if (!mobileMode && c.f){
                    let f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
                    let funcStrs = f.split(' ');
                    let funcStrs2 = c.f.split(' ');
                    let funcFont = "Default,14";
                    let dWidth = 100;
                    let totalWidth = dWidth * funcStrs.length;
                    let dLeft = (gList.size.cx - totalWidth) / 2;
                    let ddTop = 0;
                    if(divTop < cellTop){
                        ddTop = Math.max(cellBottom, bounds.b);
                    }else{
                        ddTop = Math.min(cellTop, bounds.t) - dWidth;
                    }
                    if(paint.ds == "dark"){
                        paint.fr("rgba(15,15,15,200)", dLeft, ddTop + 10, dLeft + totalWidth, ddTop + dWidth - 5);
                        paint.dr("rgb(50,50,50)", 1, 0, dLeft, ddTop + 10, dLeft + totalWidth, ddTop + dWidth - 5);
                    }else{
                        paint.fr("rgba(255,255,255,200)", dLeft, ddTop + 10, dLeft + totalWidth, ddTop + dWidth - 5);
                        paint.dr("rgb(175,175,175)", 1, 0,dLeft, ddTop + 10, dLeft + totalWidth, ddTop + dWidth - 5);
                    }   
                    for(let i = 0; i < funcStrs.length; i++){
                        let funcStr = funcStrs[i];
                        let funcSize = paint.ts(funcStr, funcFont);
                        let funcRect = null;
                        funcRect = new FR(dLeft + i * dWidth, ddTop, dLeft + (i + 1) * dWidth, ddTop + dWidth);
                        let hasFunc = false;
                        for(let j = 0; j < funcStrs2.length; j++){
                            if(funcStrs2[j] == funcStr){
                                hasFunc = true;
                                break;
                            }
                        }
                        if(paint.ds == "dark"){
                            paint.dt(funcStr, "rgb(200,200,200)", funcFont, funcRect.l + (funcRect.r - funcRect.l - funcSize.cx) / 2, funcRect.t + (funcRect.b - funcRect.t - funcSize.cy) / 2 - 15);
                            if(i != funcStrs.length - 1){
                                paint.dl("rgb(50,50,50)", 1, [2,2], funcRect.r, funcRect.t + 20, funcRect.r, funcRect.b - 14);
                            }
                        }else{
                            paint.dt(funcStr, "rgb(55,55,55)", funcFont, funcRect.l + (funcRect.r - funcRect.l - funcSize.cx) / 2, funcRect.t + (funcRect.b - funcRect.t - funcSize.cy) / 2 - 15);
                            if(i != funcStrs.length - 1){
                                paint.dl("rgb(200,200,200)", 1, [2,2], funcRect.r, funcRect.t + 20, funcRect.r, funcRect.b - 14);
                            }
                        }   
                        funcRect.l += 5;
                        funcRect.t += 5;
                        funcRect.r -= 5;
                        funcRect.b -= 5;      
                        let oX = funcRect.l + (funcRect.r - funcRect.l) / 2;
                        let oY = funcRect.t + (funcRect.b - funcRect.t) / 2 + 18;
                        let hR2 = 12;
                        let hR = 5;
                        if(replayTick == 10 && tick > 630){
                            let dTick = (720 - tick);
                            hR = hR * dTick / 90;
                            hR2 = hR2 * dTick / 90;
                        }
                        let sRect = new FR(oX - hR2, oY - hR2, oX + hR2, oY + hR2);
                        if(hasFunc){
                            drawIcon(paint, "rgb(125,125,125)", sRect, i);
                        }else{
                            drawIcon(paint, "rgb(50,50,50)", sRect, i);
                        }
                        oX = sRect.r;
                        oY = sRect.b;
                        if(hasFunc){
                            let points = new Array();
                            points.push(new FP(oX - hR - hR / 4, oY - hR + hR / 2));
                            points.push(new FP(oX - hR / 2, oY + hR));
                            points.push(new FP(oX + hR + hR / 4 + 1, oY - hR));
                            if(paint.ds == "dark"){
                                paint.dpl("rgb(100,255,41)", 2, 0, points);
                            }else{
                                paint.dpl("rgb(50,50,50)", 2, 0, points);
                            }
                        }else{
                            paint.dl("rgb(233,87,62)", 2, 0, oX - hR, oY - hR, oX + hR, oY + hR);
                            paint.dl("rgb(233,87,62)", 2, 0, oX - hR, oY + hR, oX + hR, oY - hR);
                        }
                    }
                }
            }
        }
    };

    let checkPaint = function () {
        if (clickIndex != -1) {
            if (gt.isMobile) {
                tick -= 20;
            } else {
                tick -= 12;
            }
            if (tick <= 0) {
                replayTick--;
                if(replayTick <= 0){
                    tick = 0;
                    clickIndex = -1;
                }else{
                    tick = 720;
                }
            }
            iv(gt);
        }
    };

    let clickIndex = -1;
    let tick = 0;
    let replayTick = 0;
    setInterval(checkPaint, 30);
    gt.onClickGridCell = function (grid, row, column, c, firstTouch, firstPoint, secondTouch, secondPoint, clicks) {
        let r = 1 - 210 / grid.size.cx;
        if (gt.isMobile) {
            r = 0.5;
        }
        if (c.t3 == "关于") {
            window.location.href = c.l;
        } else {
            if (firstPoint.x >= grid.size.cx * r + c.diffX && firstPoint.x <= grid.size.cx * r + c.diffX * 2) {
                if (row.index < 2) {

                } else {
                    window.location.href = c.l2;
                }
            } else if (firstPoint.x >= grid.size.cx * r && firstPoint.x <= grid.size.cx * r + c.diffX) {
                if (row.index < 2) {

                } else {
                    if (typeof (facecat) != 'undefined') {
                        window.location.href = c.l;
                    }else{
                        if(c.l.indexOf(".mp4") != -1){
                            let video = document.getElementById("myvideo");
                            video.src = c.l;
                            video.style.display = "block";
                            video.width = document.documentElement.clientWidth;
                            video.height = document.documentElement.clientHeight;
                            video.play();
                        }else{
                            window.location.href = c.l;
                        }
                    }
                }
            } else {
                clickIndex = row.index;
                tick = 720;
                if (row.index < 2) {
                    replayTick = 1;
                }else{
                    replayTick = 10;
                }
            }
        }
    };

    gt.onClickGridColumn = function (grid, column, firstTouch, firstPoint, secondTouch, secondPoint, clicks) {
        if (firstPoint.x > grid.size.cx - 50 && grid.scrollV < 150) {
            if (grid.paint.ds == "dark") {
                grid.paint.ds = "light";
            } else {
                grid.paint.ds = "dark";
            }
            if (gList.paint.ds == "dark") {
                gList.backColor = "rgb(0,0,0)";
                gList.borderColor = null;
                gList.textColor = "rgb(255,255,255)";
                gList.scrollBarColor = "rgb(100,100,100)";
            } else if (gList.paint.ds == "light") {
                gList.backColor = "rgb(230,230,230)";
                gList.borderColor = null;
                gList.textColor = "rgb(0,0,0)";
                gList.scrollBarColor = "rgb(200,200,200)";
            }
            iv(gt);
        }
    }

    let createCell = function(){
        let row = new FCGridRow;
        gList.rows.push(row);
        let c = new FCGridCell();
        row.cells.push(c);
        return c;
    }

    createCell();
    createCell();

    let drawIcon = function(paint, fillColor, imageRect, index){
        if(index == 0){
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.dl(fillColor, 1, 0, imageRect.l, imageRect.t + 12, imageRect.r - 2, imageRect.t + 12);
            paint.dl(fillColor, 1, 0, imageRect.l, imageRect.t + 18, imageRect.r - 2, imageRect.t + 18);
            paint.dl(fillColor, 1, 0, imageRect.l + 6, imageRect.t, imageRect.l + 6, imageRect.b - 2);
            paint.dl(fillColor, 1, 0, imageRect.l + 12, imageRect.t, imageRect.l + 12, imageRect.b - 2);
            paint.dl(fillColor, 1, 0, imageRect.l + 18, imageRect.t, imageRect.l + 18, imageRect.b - 2);
            paint.fr(fillColor, imageRect.l, imageRect.t, imageRect.r - 1, imageRect.t + 8);
        } else if (index == 1) {
            paint.dl(fillColor, 1, 0, imageRect.l + 12, imageRect.t, imageRect.l + 12, imageRect.b - 1);
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
        } else if (index == 7) {
            paint.drr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b, 0);
            let sFont = "Default,14";
            paint.dt("ab|", fillColor, sFont, imageRect.l, imageRect.t + 2);
        } else if (index == 3) {
            paint.fr(fillColor, imageRect.r - 5, imageRect.t, imageRect.r, imageRect.t + 5);
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.t + 6);
            paint.dr(fillColor, 1, 0, imageRect.l + 6, imageRect.t + 5, imageRect.r, imageRect.b);
            paint.dl(fillColor, 1, 0, imageRect.l + 9, imageRect.t + 10, imageRect.r - 4, imageRect.t + 10);
            paint.dl(fillColor, 1, 0, imageRect.l + 9, imageRect.t + 14, imageRect.r - 4, imageRect.t + 14);
            paint.dl(fillColor, 1, 0, imageRect.l + 9, imageRect.t + 18, imageRect.r - 4, imageRect.t + 18);
        }  else if (index == 8) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r - 5, imageRect.b - 5);
            paint.dr(fillColor, 1, 0, imageRect.l + 5, imageRect.t + 5, imageRect.r, imageRect.b);
        } else if (index == 5) {
            //绘制边线
            let points = new Array();
            points.push(new FP(imageRect.l + 4, imageRect.t));
            points.push(new FP(imageRect.l, imageRect.t));
            points.push(new FP(imageRect.l, imageRect.b));
            points.push(new FP(imageRect.r, imageRect.b));
            points.push(new FP(imageRect.r, imageRect.t));
            points.push(new FP(imageRect.l + 18, imageRect.t));
            paint.dpl(fillColor, 1, 0, points);
            let sFont = "Default,10";
            paint.dt("xy", fillColor, sFont, imageRect.l + 4, imageRect.t - 8);
        } else if (index == 6) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.dl(fillColor, 1, 0, imageRect.l, imageRect.t + 6, imageRect.r - 1, imageRect.t + 6);
            paint.dl(fillColor, 1, 0, imageRect.l, imageRect.t + 12, imageRect.r - 1, imageRect.t + 12);
            paint.dl(fillColor, 1, 0, imageRect.l, imageRect.t + 18, imageRect.r - 1, imageRect.t + 18);
        } else if (index == 2) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.dl(fillColor, 1, 0, imageRect.l, imageRect.t + 12, imageRect.r - 1, imageRect.t + 12);
            paint.dl(fillColor, 1, 0, imageRect.l + 11, imageRect.t, imageRect.l + 11, imageRect.b - 1);
        } else if (index == 10) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.dr(fillColor, 1, 0, imageRect.l + 2, imageRect.t + 2, imageRect.l + 8, imageRect.t + 6);
            paint.dr(fillColor, 1, 0, imageRect.l + 4, imageRect.t + 8, imageRect.l + 10, imageRect.t + 12);
            paint.dr(fillColor, 1, 0, imageRect.l + 4, imageRect.t + 14, imageRect.l + 10, imageRect.t + 18);
            paint.dr(fillColor, 1, 0, imageRect.l + 4, imageRect.t + 20, imageRect.l + 10, imageRect.t + 24);
            paint.dl(fillColor, 1, 0, imageRect.l + 12,  imageRect.t + 10, imageRect.l + 22, imageRect.t + 10);
            paint.dl(fillColor, 1, 0, imageRect.l + 12, imageRect.t + 16, imageRect.l + 22, imageRect.t + 16);
            paint.dl(fillColor, 1, 0, imageRect.l + 12, imageRect.t + 22, imageRect.l + 22, imageRect.t + 22);
        }else if (index == 9) {
            let sFont = "Default,10";
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.dt("1", fillColor, sFont, imageRect.l + 2, imageRect.t);
            paint.dt("2", fillColor, sFont, imageRect.l + 2, imageRect.t + 10);
            if (true) {
                let points = new Array();
                let mw = 10, mh = 10, dSize = 4;
                points.push(new FP(imageRect.l + 7 + mw, imageRect.t + mh - dSize - 2));
                points.push(new FP(imageRect.l + 7 + mw - dSize, imageRect.t + mh + dSize - 2));
                points.push(new FP(imageRect.l + 7 + mw + dSize, imageRect.t + mh + dSize - 2));
                paint.fpg(fillColor, points);
            }
            if (true) {
                let points = new Array();
                let mw = 10, mh = 10, dSize = 4;
                points.push(new FP(imageRect.l + 7 + mw, mh + imageRect.t + dSize + 10));
                points.push(new FP(imageRect.l + 7 + mw - dSize, imageRect.t + mh - dSize + 10));
                points.push(new FP(imageRect.l + 7 + mw + dSize, imageRect.t + mh - dSize + 10));
                paint.fpg(fillColor, points);
            }
        } else if (index == 4) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.fr(fillColor, imageRect.l, imageRect.t, imageRect.l + 11, imageRect.t + 6);
            paint.dr(fillColor, 1, 0, imageRect.l + 11, imageRect.t, imageRect.r, imageRect.t + 7);
        } else if (index == 11) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            paint.fr(fillColor, imageRect.l, imageRect.t, imageRect.r - 1, imageRect.t + 6);
            paint.dl(fillColor, 1, 0, imageRect.l + 3, imageRect.t + 11, imageRect.l + 9, imageRect.t + 11);
            paint.dl(fillColor, 1, 0, imageRect.l + 3, imageRect.t + 17, imageRect.l + 9, imageRect.t + 17);
            paint.dr(fillColor, 1, 0, imageRect.l + 12, imageRect.t + 9, imageRect.l + 21, imageRect.t + 13);
            paint.dr(fillColor, 1, 0, imageRect.l + 12, imageRect.t + 16, imageRect.l + 21, imageRect.t + 20);
        } else if (index == 12) {
            paint.dr(fillColor, 1, 0, imageRect.l, imageRect.t, imageRect.r, imageRect.b);
            let pWidth = (imageRect.r - imageRect.l) / 3;
            paint.fr(fillColor, imageRect.l+ 2, imageRect.t + 10, imageRect.l + pWidth, imageRect.b - 1);
            paint.fr(fillColor, imageRect.l + pWidth + 1, imageRect.t + 5, imageRect.l + pWidth * 2 - 1, imageRect.b - 1);
            paint.fr(fillColor, imageRect.l + pWidth * 2, imageRect.t + 10, imageRect.l + pWidth * 3 - 2, imageRect.b - 1);
        } 
    };

    if (true) {
        let c = createCell();
        c.t1 = "项目简介";
        c.t2 = "G";
        c.t3 = "基础框架和软件";
        c.t4 = "整体产品和业务以国产基础框架和软件为主，以替代国外信息化基建为目标，通过自研各种跨平台或跨语言的图形、通讯、服务、存储、计算、代码编辑器、脚本语言、多端互动、人工智能方面的基建设施，打造基础软件、自动化、工业软件、生产力、智能设备、嵌入式、车载、人工智能、物联网、互联网、金融量化等专业系统的研发新生态。";
        c.l = "test/video.html";
        c.l2 = "test/picture.html";
        c.lt1 = "视频";
        c.lt2 = "图片";
        c.lk = "1";
        c.i = "images/file-pdf-one.png";
        c.r = "90,70,90,80,70,70";
    }

    let surl = "https://www.jjmfc.com/software/";
    let murl = "http://www.jjmfc.com/document/movies/";
    let gurl = "https://gitee.com/facecat007/template/tree/master/";
    let furl = "https://gitee.com/facecat007/frame/tree/master/";
    let curl = "software/codemirror5/mode/facecat/";

    if (true) {
        let c = createCell();
        c.t1 = "精选案例";
        c.t2 = "P";
        c.t3 = "适用专业领域";
        c.t4 = "花卷猫的各种介绍材料均以官方出具的为准，对于他人不正确或不恰当的宣传，将会严厉制止和追责。严格保密第三方代码和资料，与自研部分做充分隔离，不会在任何地方公布合作单位。已发布的产品全部合法合规，无破解、无爬虫、无灰色、无敏感，没有资质牌照的坚决不做，不随便接项目，没有在线保存任何用户信息，互联网和金融方面的内容谨慎发展，未发布生成式AI、区块链、社交IM、互联网经营服务、toC的行情和交易软件，完全没有海外发布和业务。";
        c.l = "test/industry.html";
        c.l2 = "test/document.html";
        c.lt1 = "打开";
        c.lt2 = "文档";
        c.lk = "1";
        c.r = "90,70,90,80,70,70";
    }

    if (true) {
        let c = createCell();
        c.t1 = "作者介绍";
        c.t2 = "A";
        c.t3 = "独立开发者";
        c.t4 = "当前官网展示的所有作品都是由陶德设计和研发的，并且独立运营推广，目前并无其他的正式参与者，框架的标志名称是FaceCat，已申请著作权7项。现在仿冒我身份骗人买课，盗用我作品忽悠甲方给他项目，以及擅自把我纳入资源整合的情况非常多，作者现在正在自家农村生活和工作，长期与外界没有来往，脱离各种关系已久，与花卷猫和陶德相关的事情，如未联系本人确认，均可认为对方是骗子。为了运营安全，花卷猫将不会在GitHub等任何海外平台进行发布和推广，目前仅指定在Gitee平台公开代码和示例。";
        c.l = "test/contact.html";
        c.l2 = "https://v.qq.com/x/cover/mzc0039jcplh3gp/b3324ldhdni.html";
        c.lt1 = "打开";
        c.lt2 = "纪录片";
        c.lk = "1";
        c.r = "90,80,60,80,60,60";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫终端Windows版";
        c.t2 = "App";
        c.t3 = "开发工具(公测)";
        c.t4 = "使用花卷猫C++和C#框架的Win32-Pro版开发，包含自研的可视化设计、代码编辑器、多端互动和内存数据库等功能。该客户端可直接转为服务端，在Wifi、局域网和互联网环境下，私有部署为智能设备互联中心，所有平台的花卷猫终端都可以组队接入，任何语言的外部程序也可以与本机终端通讯，终端已被拆解为上千个基因，通过调用花卷猫研发的脚本语言，可以实现消息发送、文件传输、协作互动、云盘存储和自动化，更可以用人工智能驱动。另内嵌了微软WebView2，可以作为功能较完整的浏览器使用，解压直接使用。";
        c.l = murl + "2.mp4";
        c.l2 = surl + "FaceCat.zip";
        c.lt1 = "效果";
        c.lt2 = "下载";
        c.i = "images/windows.png";
        c.lk = "2";
        c.r = "70,70,80,80,80,70";
        c.p = "VSCode、Chrome、Qt Creator、AIoT";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫终端MacOS版";
        c.t2 = "App";
        c.t3 = "开发工具(公测)";
        c.t4 = "使用花卷猫C++框架的MacOS-Pro版开发，包含自研的可视化设计、代码编辑器、多端互动和内存数据库等功能。该客户端可直接转为服务端，在Wifi、局域网和互联网环境下，私有部署为智能设备互联中心，所有平台的花卷猫终端都可以组队接入，任何语言的外部程序也可以与本机终端通讯，终端已被拆解为上千个基因，通过调用花卷猫研发的脚本语言，可以实现消息发送、文件传输、协作互动、云盘存储和自动化，更可以用人工智能驱动。另内嵌了WkWebView，可以作为功能较完整的浏览器使用，打开dmg拖拽到应用中，并到系统偏好设置中添加信任。";
        c.l = murl + "3.mp4";
        c.l2 = surl + "FaceCat.dmg";
        c.i = "images/macos.png";
        c.lt1 = "效果";
        c.lt2 = "下载";
        c.lk = "2";
        c.r = "70,70,80,80,80,70";
        c.p = "VSCode、Chrome、Qt Creator、AIoT";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫终端安卓版";
        c.t2 = "App";
        c.t3 = "开发工具(公测)";
        c.t4 = "使用花卷猫Java框架的Android-Pro版开发，包含自研的代码编辑器、多端互动和内存数据库等功能。该客户端可直接转为服务端，在Wifi、局域网和互联网环境下，私有部署为智能设备互联中心，所有平台的花卷猫终端都可以组队接入，任何语言的外部程序也可以与本机终端通讯，终端已被拆解为上千个基因，通过调用花卷猫研发的脚本语言，可以实现消息发送、文件传输、协作互动、云盘存储和自动化，更可以用人工智能驱动。另内嵌了WebView，可以作为功能较完整的浏览器使用，直接下载安装，每次提示更新后需要手动安装。";
        c.l = murl + "4.mp4";
        c.l2 = surl + "FaceCat.apk";
        c.i = "images/android.png";
        c.lt1 = "效果";
        c.lt2 = "下载";
        c.lk = "2";
        c.r = "10,70,80,80,70,70";
        c.p = "VSCode、Chrome、Qt Creator、AIoT";
    }


    if (true) {
        let c = createCell();
        c.t1 = "花卷猫终端iOS版";
        c.t2 = "App";
        c.t3 = "开发工具(公测)";
        c.t4 = "使用花卷猫C++框架的iOS-Pro版开发，包含自研的代码编辑器、多端互动和内存数据库等功能。该客户端可直接转为服务端，在Wifi、局域网和互联网环境下，私有部署为智能设备互联中心，所有平台的花卷猫终端都可以组队接入，任何语言的外部程序也可以与本机终端通讯，终端已被拆解为上千个基因，通过调用花卷猫研发的脚本语言，可以实现消息发送、文件传输、协作互动、云盘存储和自动化，更可以用人工智能驱动。另内嵌了WkWebView，可以作为功能较完整的浏览器使用，未上线AppStore，由用户自己用XCode安装。";
        c.l = murl + "10.mp4";
        c.l2 = surl + "iosapp.zip";
        c.i = "images/apple.png";
        c.lt1 = "效果";
        c.lt2 = "下载";
        c.lk = "2";
        c.r = "10,70,80,80,70,70";
        c.p = "VSCode、Chrome、Qt Creator、AIoT";
    }

if (true) {
        let c = createCell();
        c.t1 = "花卷猫多端互动Ubuntu版";
        c.t2 = "App";
        c.t3 = "开发工具(公测)";
        c.t4 = "使用花卷猫Java框架的Swing-Pro版开发，该客户端可直接转为服务端，在Wifi、局域网和互联网环境下，私有部署为智能设备互联中心，所有平台的花卷猫终端都可以组队接入，任何语言的外部程序也可以与本机终端通讯，终端已被拆解为上千个基因，通过调用花卷猫研发的脚本语言，可以实现消息发送、文件传输、协作互动、云盘存储和自动化，更可以用人工智能驱动，包含完整的源代码，用户可以自己编译运行。";
        c.l = murl + "14.mp4";
        c.l2 = gurl + "java/neuronclient";
        c.i = "images/linux.png";
        c.lt1 = "效果";
        c.lt2 = "下载";
        c.lk = "2";
        c.r = "1,1,30,1,1,1";
        c.p = "AIoT";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Win32 C++框架";
        c.t2 = "Pro";
        c.t3 = "客户端+服务端框架";
        c.t4 = "用于制作要求较高的Windows客户端和服务，全部使用C++构建，调用原生底层API，整个界面仅使用单个窗体进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已分别对接GDI和GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。通讯服务方面完全使用底层接口封装，包含长短连接，支持完成端口。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cpp.html";
        c.l2 = surl + "facecat_cpp.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cpp2.png";
        c.r = "90,100,100,70,95,100";
        c.lk = "7";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Qt、MFC、DuiLib、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "1";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Java-Android框架";
        c.t2 = "Pro";
        c.t3 = "App+服务端框架";
        c.t4 = "用于制作要求较高的安卓App，全部使用Java构建，调用原生底层API，整个界面仅使用单个View进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Java直接获取和操作元素。通讯服务方面使用原始接口封装，包含长短连接，支持NIO。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "java.html";
        c.l2 = surl + "facecat_android.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/android.png";
        c.r = "85,80,80,80,95,90";
        c.lk = "7";
        c.p = "Android";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "安卓原生、Netty";
        c.s = true;
        c.n = "2";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Java-Swing框架";
        c.t2 = "Pro";
        c.t3 = "客户端+服务端框架";
        c.t4 = "用于制作要求较高的Windows/Linux客户端和服务，全部使用Java构建，调用原生底层API，整个界面仅使用单个JPanel进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Java直接获取和操作元素。通讯服务方面使用原始接口封装，包含长短连接，支持NIO。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "java.html";
        c.l2 = surl + "facecat_swing.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/java.png";
        c.r = "75,60,80,70,95,95";
        c.lk = "7";
        c.p = "Windows、Linux"
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "JavaFx、Swing、Netty";
        c.s = true;
        c.n = "3";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫MacOS C++框架";
        c.t2 = "Pro";
        c.t3 = "客户端+服务端框架";
        c.t4 = "用于制作要求较高的MacOS客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个NSView进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。通讯服务方面完全使用底层接口封装，包含长短连接。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cpp.html";
        c.l2 = surl + "facecat_macos.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/macos.png";
        c.r = "100,90,95,70,95,95";
        c.lk = "7";
        c.p = "MacOS"
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "4";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫iOS C++框架";
        c.t2 = "Pro";
        c.t3 = "App+服务端框架";
        c.t4 = "用于制作要求较高的iOS-App，全部使用C++构建，调用原生底层API，整个界面仅使用单个UIView进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。通讯服务方面完全使用底层接口封装，包含长短连接。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cpp.html";
        c.l2 = surl + "facecat_ios.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/ios.png";
        c.r = "100,90,95,70,95,95";
        c.lk = "7";
        c.p = "iOS"
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "5";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫C#框架";
        c.t2 = "Pro";
        c.t3 = "客户端+服务端框架";
        c.t4 = "用于制作要求较高的Windows客户端，全部使用C#构建，调用原生底层API，整个界面仅使用单个Control进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已分别对接GDI和GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。通讯服务方面使用原始接口封装，包含长短连接，支持完成端口。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cs.html";
        c.l2 = surl + "facecat_cs.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cs2.png";
        c.r = "85,90,90,80,95,90";
        c.lk = "7";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Avalonia、Maui、Devexpress、DotNetty";
        c.s = true;
        c.n = "6";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫鸿蒙框架";
        c.t2 = "Pro";
        c.t3 = "App+服务端框架";
        c.t4 = "用于制作要求较高的鸿蒙原生应用，全部使用Java构建，调用原生底层API，整个界面仅使用单个Component进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Java直接获取和操作元素。通讯服务方面使用原始接口封装，包含长短连接，支持NIO。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "java.html";
        c.l2 = surl + "facecat_ohos.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/hos.png";
        c.r = "85,80,80,80,95,80";
        c.lk = "7";
        c.p = "HarmonyOS";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "鸿蒙原生、Netty";
        c.s = true;
        c.n = "7";
    }

    
if (true) {
        let c = createCell();
        c.t1 = "花卷猫Kotlin框架";
        c.t2 = "Pro";
        c.t3 = "App+服务端框架";
        c.t4 = "用于制作要求较高的安卓App，使用Kotlin构建，调用原生底层API，整个界面仅使用单个View进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Kotlin直接获取和操作元素。通讯服务方面使用原始接口封装，包含长短连接，支持NIO。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "kotlin.html";
        c.l2 = surl + "facecat_kotlin.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/kotlin.png";
        c.r = "85,80,80,70,95,70";
        c.lk = "7";
        c.p = "Android";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "安卓原生、Netty";
        c.s = true;
        c.n = "8";
    }
    
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Ubuntu C++框架";
        c.t2 = "Pro";
        c.t3 = "客户端+服务端框架";
        c.t4 = "用于制作要求较高的Ubuntu客户端和服务，全部使用C++构建，调用原生底层API，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接SDL2，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。通讯服务方面完全使用底层接口封装，包含长短连接，支持NIO。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cpp.html";
        c.l2 = "document/frame/pic1.jpg";
        c.lt1 = "运行";
        c.lt2 = "图片";
        c.i = "images/ubuntu.png";
        c.r = "80,100,100,70,95,90";
        c.lk = "7";
        c.p = "Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "9";
        
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Android C++框架";
        c.t2 = "Pro";
        c.t3 = "App+服务端框架";
        c.t4 = "用于制作要求较高的Android客户端和服务，全部使用C++构建，调用原生底层API，整个界面仅使用单个View进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas重绘，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。通讯服务方面完全使用底层接口封装，包含长短连接。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cpp.html";
        c.l2 = "document/frame/pic2.jpg";
        c.lt1 = "运行";
        c.lt2 = "图片";
        c.i = "images/android.png";
        c.r = "85,80,80,70,95,70";
        c.lk = "7";
        c.p = "Android";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "10";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫鸿蒙C++框架";
        c.t2 = "Pro";
        c.t3 = "App+服务端框架";
        c.t4 = "用于制作要求较高的HarmonyOS客户端和服务，全部使用C++构建，调用原生底层API，整个界面仅使用单个Component进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas重绘，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。通讯服务方面完全使用底层接口封装，包含长短连接。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "cpp.html";
        c.l2 = "document/frame/pic3.jpg";
        c.lt1 = "运行";
        c.lt2 = "图片";
        c.i = "images/hos.png";
        c.r = "85,80,80,70,95,70";
        c.lk = "7";
        c.p = "HarmonyOS";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "11";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫JavaFx框架";
        c.t2 = "Pro";
        c.t3 = "客户端+服务端框架";
        c.t4 = "用于制作要求较高的Windows/Linux客户端和服务，全部使用Java构建，调用原生底层API，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GraphicsContext绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Java直接获取和操作元素。通讯服务方面使用原始接口封装，包含长短连接，支持NIO。前后端均已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = curl + "java.html";
        c.l2 = surl + "facecat_javafx.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/java.png";
        c.r = "85,60,90,80,95,90";
        c.lk = "7";
        c.p = "Windows、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入 镜像虫洞 内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "JavaFx、Swing、Netty";
        c.s = true;
        c.n = "12";
    }
    
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫多端互动服务端";
        c.t2 = "Pro";
        c.t3 = "后端服务框架";
        c.t4 = "用于私有部署多端互动服务，使用该服务可以让不同的设备间收发消息和互动联合，使用Java构建，已嵌入和使用花卷猫自研的编程语言引擎FCScript。";
        c.l = "software/desc/neuron.txt";
        c.l2 = gurl + "java/neuron";
        c.lt1 = "介绍";
        c.lt2 = "代码";
        c.i = "images/java.png";
        c.r = "80,80,80,80,70,80";
        c.lk = "7";
        c.p = "Windows、Linux";
        c.f = "内存数据库 脚本语言 短连接服务 长连接服务";
        c.d = "IDEA、NetBeans、Ellipse";
    }
    
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Win32 C++框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个窗体进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI和GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_cpp2";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cpp2.png";
        c.r = "90,100,100,70,80,100";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Qt、MFC、DuiLib、wxWidgets、Gtk";
        c.s = true;
        c.n = "13";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫C#框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C#构建，调用原生底层API，整个界面仅使用单个Control进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_cs2";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cs2.png";
        c.r = "85,90,90,80,80,90";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "14";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫JavaScript框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作Html5的前端，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "javascript.html";
        c.l2 = furl + "facecat_js";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/javascript.png";
        c.r = "85,70,95,95,80,90";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "15";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Python框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows和MacOS客户端，使用Python构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已分别对接GDI、GDI+、Skia、Tkinter、wxPython和Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "python.html";
        c.l2 = furl + "facecat_py/win32";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/python.png";
        c.r = "85,90,90,95,80,90";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "16";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Rust框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作Html5的前端，使用Wasm技术，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Rust直接获取和操作元素。";
        c.l = curl + "rust.html";
        c.l2 = furl + "facecat_rust";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/rust.png";
        c.r = "85,80,80,50,50,70";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Dioxus、GTK";
        c.s = true;
        c.n = "17";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Flutter框架";
        c.t2 = "Light";
        c.t3 = "App框架";
        c.t4 = "用于制作跨平台的前端，使用Dart构建，整个界面仅使用单个CustomPaint进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Dart直接获取和操作元素。";
        c.l = curl + "flutter.html";
        c.l2 = furl + "facecat_flutter";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/flutter.png";
        c.r = "80,70,70,70,80,90";
        c.lk = "3";
        c.p = "Windows、MacOS、iOS、Linux、Android、Web";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Flutter原生";
        c.s = true;
        c.n = "18";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫SwiftUI框架";
        c.t2 = "Light";
        c.t3 = "客户端+App框架";
        c.t4 = "用于制作MacOS和iOS的原生客户端，使用Swift构建，调用原生底层API，整个界面仅使用单个UIView或NSView进行重绘，所有内部组件都是虚拟出来的，触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Swift直接获取和操作元素。";
        c.l = curl + "swift.html";
        c.l2 = furl + "facecat_swiftui";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/swiftui.png";
        c.r = "95,80,80,70,80,80";
        c.lk = "3";
        c.p = "MacOS、iOS";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "SwiftUI原生";
        c.s = true;
        c.n = "19";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Go框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，以及wasm的前端，使用Go构建，整个界面仅使用单个窗体或Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI、GDI+、Skia和Html5，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Go直接获取和操作元素。";
        c.l = curl + "go.html";
        c.l2 = furl + "facecat_go/win32";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/go.png";
        c.r = "85,90,90,70,70,70";
        c.lk = "3";
        c.p = "Windows、Web";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Wails、Fyne";
        c.s = true;
        c.n = "20";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫TypeScript框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作前端应用，使用TypeScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配TypeScript直接获取和操作元素。";
        c.l = curl + "typescript.html";
        c.l2 = furl + "facecat_ts";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/ts.png";
        c.r = "85,70,80,70,80,70";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "TypeScript<Canvas>";
        c.s = true;
        c.n = "21";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Vue框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作前端应用，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "vue.html";
        c.l2 = furl + "facecat_vue";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/vue.png";
        c.r = "85,70,80,90,80,80";
        c.lk = "3";
        c.p = "WebApp";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "22";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫ReactNative框架";
        c.t2 = "Light";
        c.t3 = "App框架";
        c.t4 = "用于制作前端应用，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "reactnative.html";
        c.l2 = furl + "facecat_reactnative";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/react.png";
        c.r = "80,70,80,60,80,80";
        c.lk = "3";
        c.p = "iOS、Android";
        c.f = "虚拟视图 可视化设计 事件回调 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "23";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫UniApp框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作UniApp的前端应用，使用JavaScript构建， 整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "uniapp.html";
        c.l2 = furl + "facecat_uniapp";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/uniapp.png";
        c.r = "70,70,80,90,80,80";
        c.lk = "3";
        c.p = "WebApp";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "24";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫小程序框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作小程序的前端应用，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "wechat.html";
        c.l2 = furl + "facecat_wechat";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/mini.png";
        c.r = "80,70,80,70,80,80";
        c.lk = "3";
        c.p = "微信小程序";
        c.f = "虚拟视图 可视化设计 事件回调 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "25";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫R框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，使用JavaScript来构建界面，可调用R代码";
        c.l = curl + "javascript.html";
        c.l2 = furl + "facecat_r";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/r.png";
        c.r = "85,60,60,50,80,80";
        c.lk = "3";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "26";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Ruby框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，使用Ruby构建，整个界面仅使用单个窗体进行重绘，直接对接Windows消息，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI和GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Ruby直接获取和操作元素。";
        c.l = curl + "ruby.html";
        c.l2 = furl + "facecat_ruby";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/ruby.png";
        c.r = "85,90,90,70,80,80";
        c.lk = "3";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "Shoes、FXRuby";
        c.s = true;
        c.n = "27";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫PHP框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作PHP的前端，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "javascript.html";
        c.l2 = furl + "facecat_php";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/php.png";
        c.r = "85,70,90,95,80,80";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "28";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Electron框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，使用Electron构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "electron.html";
        c.l2 = furl + "facecat_electron";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/electron.png";
        c.r = "85,70,50,80,80,80";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "29";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Tauri框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，使用Tauri构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "tauri.html";
        c.l2 = furl + "facecat_tauri";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/tauri.png";
        c.r = "85,70,80,80,80,80";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "30";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Next.js框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作Next.js的前端，使用JavaScript和React构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "nextjs.html";
        c.l2 = furl + "facecat_nextjs";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/nextjs.png";
        c.r = "85,70,80,80,80,80";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "31";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫鸿蒙Arkts框架";
        c.t2 = "Light";
        c.t3 = "App框架";
        c.t4 = "用于制作HarmonyOS的前端应用，使用Arkts，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配TypeScript直接获取和操作元素。";
        c.l = curl + "arkts.html";
        c.l2 = furl + "facecat_arkts";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/arkts.png";
        c.r = "80,70,80,60,70,70";
        c.lk = "3";
        c.p = "HarmonyOS";
        c.f = "虚拟视图 可视化设计 事件回调 手势触摸 矢量缩放 键盘输入";
        c.d = "鸿蒙Artks原生";
        c.s = true;
        c.n = "32";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫UniAppX框架";
        c.t2 = "Light";
        c.t3 = "App框架";
        c.t4 = "用于制作UniAppX的前端应用，使用TypeScript，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配TypeScript直接获取和操作元素。";
        c.l = curl + "uniappx.html";
        c.l2 = furl + "facecat_uniappx";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/uniapp.png";
        c.r = "80,70,80,50,60,50";
        c.lk = "3";
        c.p = "iOS、Android";
        c.f = "虚拟视图 事件回调 手势触摸";
        c.d = "TypeScript<Canvas>";
        c.s = true;
        c.n = "33";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Qt框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，使用C++构建，整个界面仅使用单个Widget进行重绘，所有内部组件都是虚拟出来的，鼠标和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接QPainter和QGraphicsView，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_qt/cpp";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/qt.png";
        c.r = "90,90,70,60,95,90";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux、iOS、Android";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、MFC、wxWidgets、Gtk";
        c.s = true;
        c.n = "34";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫PyQt框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，使用PyQt构建，整个界面仅使用单个Widget进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接QPainter，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "pyqt.html";
        c.l2 = furl + "facecat_qt/pyqt";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/qt.png";
        c.r = "85,80,70,90,95,90";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "35";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫PySide框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，使用PySide构建，整个界面仅使用单个QMainWindow进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接QPainter，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "pyside.html";
        c.l2 = furl + "facecat_qt/pyside";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/qt.png";
        c.r = "85,80,70,90,95,90";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "36";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Tkinter框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Python的客户端，使用Tkinter构建，整个界面仅使用单Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "tkinter.html";
        c.l2 = furl + "facecat_py/tkinter";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/python.png";
        c.r = "70,80,90,90,95,90";
        c.lk = "3";
        c.p = "Windows、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "37";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫wxPython框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Python的客户端，使用wxPython构建，整个界面仅使用单Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接DC，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "wxpython.html";
        c.l2 = furl + "facecat_py/wxpython";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/wxwidgets.png";
        c.r = "80,80,90,90,95,90";
        c.lk = "3";
        c.p = "Windows、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "38";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Maui框架";
        c.t2 = "Light";
        c.t3 = "客户端+App框架";
        c.t4 = "用于制作.Net的跨平台客户端，全部使用C#构建，整个界面仅使用单个GraphicsView进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标和触摸操作均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_maui";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/maui.png";
        c.r = "85,70,60,80,50,70";
        c.lk = "3";
        c.p = "Windows、MacOS、iOS、Android";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 原生附着";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "39";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫WPF框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作WPF客户端，全部使用C#构建，整个界面仅使用单个Control进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标和输入操作均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接SkiaSharp，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_wpf";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/wpf.png";
        c.r = "90,70,80,80,80,80";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "40";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Avalonia框架";
        c.t2 = "Light";
        c.t3 = "客户端+App框架";
        c.t4 = "用于制作Avalonia客户端，全部使用C#构建，整个界面仅使用单个UserControl进行重绘，所有内部组件都是虚拟出来的，鼠标和触摸操作均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接DrawingContext，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_avalonia";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/avalonia.png";
        c.r = "85,60,80,80,60,80";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux、iOS、Android";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 原生附着";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "41";
    }
    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Devexpress框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Devexpress客户端，全部使用C#构建，整个界面仅使用单个窗体进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标和输入操作均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_devexpress";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/devexpress.png";
        c.r = "85,80,60,80,80,70";
        c.lk = "3";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "42";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫WinUI框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C#构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_winui";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/winui.png";
        c.r = "85,80,70,80,70,70";
        c.lk = "3";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 原生附着";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "43";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Blazor框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作ASP.NET，全部使用C#构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标和手势操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Canvas，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_blazor";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/blazor.png";
        c.r = "80,80,70,80,70,70";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 事件回调";
        c.d = "ASP.NET";
        c.s = true;
        c.n = "44";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Pascal框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，使用Pascal构建，整个界面仅使用单个窗体进行重绘，直接对接Windows消息，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI和GDI+，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Pascal直接获取和操作元素。";
        c.l = curl + "pascal.html";
        c.l2 = furl + "facecat_pascal";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/pascal.png";
        c.r = "85,90,90,50,60,80";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "Delphi、Lazarus";
        c.s = true;
        c.n = "45";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫MFC框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个窗体进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标和输入操作均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_mfc";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/mfc.png";
        c.r = "90,100,100,70,80,80";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、wxWidgets、MFC";
        c.s = true;
        c.n = "46";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Duilib框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接GDI，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_duilib";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/duilib.png";
        c.r = "90,95,95,70,80,80";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、wxWidgets、MFC";
        c.s = true;
        c.n = "47";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫wxWidgets框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，全部使用C++构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接DC，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_wxwidgets";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/wxwidgets.png";
        c.r = "90,80,85,70,80,80";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、wxWidgets、MFC";
        c.s = true;
        c.n = "48";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫EasyX框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，全部使用C++构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接EasyX绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_easyx";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cpp2.png";
        c.r = "90,80,85,70,80,80";
        c.lk = "3";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击";
        c.d = "Qt、Duilib、wxWidgets、MFC";
        c.s = true;
        c.n = "49";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫gtk+框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，全部使用C++构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标和输出操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Cairo绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_gtk";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/gtk.png";
        c.r = "90,80,85,70,80,80";
        c.lk = "3";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、wxWidgets、MFC";
        c.s = true;
        c.n = "50";
    }


    if (true) {
        let c = createCell();
        c.t1 = "花卷猫VB.NET框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，使用VB.NET构建，整个界面使用单个窗体重绘，内部元素的鼠标和输操作均为模拟，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配VB直接获取和操作元素。";
        c.l = curl + "xml.html";
        c.l2 = surl + "facecat_vb.zip";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/vb.png";
        c.r = "85,90,80,70,80,80";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Winform、WPF";
        c.s = true;
        c.n = "51";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Pyobjc框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作MacOS客户端，使用Python构建，整个界面仅使用单个窗体进行重绘，使用pyobjc，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "pyobjc.html";
        c.l2 = furl + "facecat_py/macos";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/python.png";
        c.r = "85,90,90,95,80,90";
        c.lk = "3";
        c.p = "MacOS";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "52";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Go-Wasm框架";
        c.t2 = "Light";
        c.t3 = "前端框架";
        c.t4 = "用于制作wasm的前端，使用Go构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Html5，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Go直接获取和操作元素。";
        c.l = curl + "gowasm.html";
        c.l2 = furl + "facecat_go/wasm";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/go.png";
        c.r = "85,90,90,70,70,70";
        c.lk = "3";
        c.p = "Web";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Wails、Fyne";
        c.s = true;
        c.n = "53";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫arrdio框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作arrdio的Html5客户端，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素。";
        c.l = curl + "javascript.html";
        c.l2 = furl + "facecat_arrdio";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/arrdio.png";
        c.r = "85,70,95,95,80,90";
        c.lk = "3";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "JavaScript<Canvas>";
        c.s = true;
        c.n = "54";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫GtkSharp框架";
        c.t2 = "Light";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，全部使用C#构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标和输出操作为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Cairo绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facecat_gtksharp";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/gtk.png";
        c.r = "90,80,85,70,80,80";
        c.lk = "3";
        c.p = "Windows、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "55";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Lua框架";
        c.t2 = "Light";
        c.t3 = "基础框架";
        c.t4 = "通过lua51与界面进行通讯，相互调用。";
        c.l = curl + "xml.html";
        c.l2 = "document/frame/pic4.jpg";
        c.lt1 = "运行";
        c.lt2 = "图片";
        c.i = "images/lua.png";
        c.lk = "3";
        c.p = "Windows(XP及以上)";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 键盘输入";
        c.d = "Winform、WPF";
        c.s = true;
        c.n = "56";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫QGraphicsView框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作客户端，使用Python和QGraphicsView构建，整个界面仅使用单个QGraphicsItem进行重绘，所有内部组件都是虚拟出来的，鼠标操作为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接QPainter，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "qgraphicsview.html";
        c.l2 = furl + "facecat_qt/pygv";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/qt.png";
        c.r = "95,80,80,90,95,80";
        c.lk = "4";
        c.p = "Windows、MacOS、Linux";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "57";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Win32 Skia C++框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个句柄进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Skia，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_skiacpp";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cpp2.png";
        c.r = "100,80,90,70,80,80";
        c.lk = "4";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、MFC、wxWidgets、Gtk";
        c.s = true;
        c.n = "58";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Ubuntu Skia C++框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Ubuntu客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个句柄进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Skia，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_skiaucpp";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/ubuntu.png";
        c.r = "100,80,90,70,80,80";
        c.lk = "4";
        c.p = "Linux";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Qt、Duilib、MFC、wxWidgets、Gtk";
        c.s = true;
        c.n = "59";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Win32 Skia C#框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，全部使用C#构建，调用原生底层API，整个界面仅使用单个Control进行重绘，只有一个句柄，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Skia，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C#直接获取和操作元素。";
        c.l = curl + "cs.html";
        c.l2 = furl + "facacat_skiasharp";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cs2.png";
        c.r = "100,80,80,80,80,80";
        c.lk = "4";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Avalonia、Maui、Devexpress、WPF";
        c.s = true;
        c.n = "60";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Python Skia框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，使用Python构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Skia，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Python直接获取和操作元素。";
        c.l = curl + "python.html";
        c.l2 = "https://gitee.com/facecat007/template2/tree/master/python/ctp_fast";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/python.png";
        c.r = "95,80,80,90,80,80";
        c.lk = "4";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "PyQt、Tkinter、wxPython";
        c.s = true;
        c.n = "61";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Go Skia框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows客户端，使用Go构建，整个界面仅使用单个窗体进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Skia，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配Go直接获取和操作元素。";
        c.l = curl + "go.html";
        c.l2 = "https://gitee.com/facecat007/template2/tree/master/go/ctp_fast";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/go.png";
        c.r = "95,80,80,80,80,80";
        c.lk = "4";
        c.p = "Windows";
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 矢量缩放 键盘输入";
        c.d = "Wails、Fyne";
        c.s = true;
        c.n = "62";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫MacOS C++框架";
        c.t2 = "Fast";
        c.t3 = "客户端框架";
        c.t4 = "用于制作MacOS客户端，全部使用C++构建，调用原生底层API，整个界面仅使用单个NSView进行重绘，所有内部组件都是虚拟出来的，鼠标、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_macos2";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/macos.png";
        c.r = "100,90,95,70,95,95";
        c.lk = "4";
        c.p = "MacOS"
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 鼠标点击 矢量缩放 键盘输入";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "63";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫iOS C++框架";
        c.t2 = "Fast";
        c.t3 = "App框架";
        c.t4 = "用于制作iOS-App，全部使用C++构建，调用原生底层API，整个界面仅使用单个UIView进行重绘，所有内部组件都是虚拟出来的，触摸、输入和滚动加速均为模拟。绘图代码与框架完全隔离，可以轻易更换，已对接Quartz2D，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配C++直接获取和操作元素。";
        c.l = curl + "cpp.html";
        c.l2 = furl + "facecat_ios2";
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/ios.png";
        c.r = "100,90,95,70,95,95";
        c.lk = "4";
        c.p = "iOS"
        c.f = "虚拟视图 可视化设计 事件回调 跨线程信号 手势触摸 矢量缩放 键盘输入";
        c.d = "Qt、wxWidgets、Gtk、Boost";
        c.s = true;
        c.n = "64";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Python+WebView2";
        c.t2 = "Hybrid";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows的客户端，由Python启动WebView2，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素，可以同Python相互发消息。";
        c.l = curl + "javascript.html";
        c.l2 = "https://gitee.com/facecat007/template/tree/master/python/webview2"
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/python.png";
        c.r = "85,70,95,95,80,90";
        c.lk = "5";
        c.p = "Windows"
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Electron、Tauri";
        c.s = true;
        c.n = "65";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Go+WebView2";
        c.t2 = "Hybrid";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows的客户端，由Go启动WebView2，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素，可以同Go相互发消息。";
        c.l = curl + "javascript.html";
        c.l2 = "https://gitee.com/facecat007/template/tree/master/go/webview2"
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/go.png";
        c.r = "85,70,95,95,80,90";
        c.lk = "5";
        c.p = "Windows"
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Electron、Tauri";
        c.s = true;
        c.n = "66";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫C#+WebView2";
        c.t2 = "Hybrid";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows的客户端，由C#启动WebView2，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素，可以同C#相互发消息。";
        c.l = curl + "javascript.html";
        c.l2 = "https://gitee.com/facecat007/template/tree/master/csharp/webview2"
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cs2.png";
        c.r = "85,70,95,95,80,90";
        c.lk = "5";
        c.p = "Windows"
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Electron、Tauri";
        c.s = true;
        c.n = "67";
    }

    if (true) {
        let c = createCell();
        c.t1 = "花卷猫Cpp+WebView2";
        c.t2 = "Hybrid";
        c.t3 = "客户端框架";
        c.t4 = "用于制作Windows的客户端，由C++启动WebView2，使用JavaScript构建，整个界面仅使用单个Canvas进行重绘，所有内部组件都是虚拟出来的，鼠标、触摸和滚动加速均为模拟，输入框为原生附着。绘图代码与框架完全隔离，可以轻易更换，已对接Html5绘图，使用可视化工具来设计界面，其配置文件可以在多达20种语言和70个不同技术版本中通用，搭配JavaScript直接获取和操作元素，可以同C++相互发消息。";
        c.l = curl + "javascript.html";
        c.l2 = "https://gitee.com/facecat007/template/tree/master/cpp/webview2"
        c.lt1 = "运行";
        c.lt2 = "代码";
        c.i = "images/cpp2.png";
        c.r = "85,70,95,95,80,90";
        c.lk = "5";
        c.p = "Windows"
        c.f = "虚拟视图 可视化设计 事件回调 鼠标点击 手势触摸 矢量缩放 键盘输入";
        c.d = "Electron、Tauri";
        c.s = true;
        c.n = "68";
    }

    if (true) {
        let c = createCell();
        c.t1 = "WebView2Bridge";
        c.t2 = "Hybrid";
        c.t3 = "客户端框架";
        c.t4 = "使用C++开发，对接微软WebView2组件，并提供与多语言通讯的接口，用户可以自行编译或修改。";
        c.l = "document/templates/facecatbridge.jpg";
        c.l2 = "https://gitee.com/facecat007/template/tree/master/cpp/facecatbridge"
        c.lt1 = "图片";
        c.lt2 = "代码";
        c.i = "images/cpp2.png";
        c.lk = "5";
        c.p = "Windows"
        c.d = "Electron、Tauri";
        c.s = true;
    }

    if (true) {
        let c = createCell();
        c.t1 = "研发历史";
        c.t2 = "H";
        c.t3 = "图片和视频";
        c.t4 = "该框架长期属于作者个人的最优良试验田，自由发挥，从未受利益驱使改变开发方向。基础框架、生态工具和后台服务代码原创度均高于99%，规模庞大，独有代码300万行，从架构，命名到细节均不与任何第三方重复。多数版本仅需操作系统和语言基础SDK支持，无须更多第三方依赖，在国产原创度方面接受一切公开质疑和检验。";
        c.l = "https://mp.weixin.qq.com/s/y_x4ZJPQo-SPx0imjW4JZQ";
        c.l2 = "";
        c.lt1 = "介绍";
        c.lt2 = "";
        c.lk = "1";
        c.r = "90,80,60,80,60,60";
    }

    if (true) {
        let c = createCell();
        c.t1 = "实物股东";
        c.t2 = "F";
        c.t3 = "资金和设备";
        c.t4 = "在困难和关键时刻对花卷猫的援助，都将被永远镌刻在官网中，按时间先后顺序排列，后续会优先获得有价值且无风险的超值回报。";
        c.l = "test/thanks.html";
        c.l2 = "";
        c.lt1 = "公示";
        c.lt2 = "";
        c.lk = "1";
        c.r = "90,80,60,80,60,60";
    }

    if (true) {
        let c = createCell();
        c.t1 = "头脑股东";
        c.t2 = "B";
        c.t3 = "创意和想法";
        c.t4 = "在任何时候对花卷猫的重要有效建议和点拨，都将被永远镌刻在官网中，按时间先后顺序排列，后续将获得适当的回报得适当的回报。";
        c.l = "test/ideas.html";
        c.l2 = "";
        c.lt1 = "公示";
        c.lt2 = "";
        c.lk = "1";
        c.r = "90,80,60,80,60,60";
    }

    if (true) {
        let c = createCell();
        c.t1 = "沪ICP备2021003600号 热线电话：15921975627";
        c.t2 = "";
        c.t3 = "关于";
        c.t4 = "";
        c.l = "https://beian.miit.gov.cn/";
        c.l2 = "";
        c.lt1 = "";
        c.lt2 = "";
        c.lk = "1";
    }

    for(let i = 0; i < gList.rows.length; i++){
        gList.rows[i].cells[0].font = "Default,16"
    }
    uvd(gt.views);
    //刷新界面
    iv(gt);
    setInterval(checkGridDragScroll, 20);
    </script>
</body>
</html>
